blob: 95316b08613a33b1c1a16ff96cc64e7f0180d204 [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Duncan Lauried9af3ce2016-05-08 18:15:25 -07002
Furquan Shaikhd1130af2020-04-23 12:51:42 -07003#include <assert.h>
Duncan Lauried9af3ce2016-05-08 18:15:25 -07004#include <string.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07005#include <acpi/acpi.h>
6#include <acpi/acpi_device.h>
7#include <acpi/acpigen.h>
Tim Wawrzynczakd40a4c22021-02-25 13:14:49 -07008#include <acpi/acpigen_pci.h>
Duncan Lauried9af3ce2016-05-08 18:15:25 -07009#include <device/device.h>
Elyes HAOUAS70a03dd2019-12-02 20:47:50 +010010#include <stdlib.h>
Elyes HAOUASa83a7db2020-07-22 11:42:53 +020011#include <types.h>
Patrick Rudolphc83bab62019-12-13 12:16:06 +010012#include <crc_byte.h>
13
Julius Wernercd49cce2019-03-05 16:53:33 -080014#if CONFIG(GENERIC_GPIO_LIB)
Duncan Lauriecfb6ea72016-05-09 17:08:38 -070015#include <gpio.h>
16#endif
Duncan Lauried9af3ce2016-05-08 18:15:25 -070017
Duncan Laurieffc99902016-07-02 19:56:06 -070018#define ACPI_DP_UUID "daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
19#define ACPI_DP_CHILD_UUID "dbb8e3e6-5886-4ba6-8795-1319f52a966b"
Duncan Laurie559e9472016-05-10 13:18:17 -070020
Kapil Porwal75436272022-11-28 17:25:48 +053021/*
22 * Below properties are defined at
23 * https://docs.microsoft.com/en-us/windows-hardware/drivers/pci/dsd-for-pcie-root-ports
24 */
25#define ACPI_DSD_EXTERNAL_FACING_PORT_UUID "EFCC06CC-73AC-4BC3-BFF0-76143807C389"
26#define ACPI_DSD_EXTERNAL_FACING_PORT_NAME "ExternalFacingPort"
27
28#define ACPI_DSD_HOTPLUG_IN_D3_UUID "6211E2C0-58A3-4AF3-90E1-927A4E0C55A4"
29#define ACPI_DSD_HOTPLUG_IN_D3_NAME "HotPlugSupportInD3"
30
31/* ID for the DmaProperty _DSD */
32#define ACPI_DSD_DMA_PROPERTY_UUID "70D24161-6DD5-4C9E-8070-705531292865"
33#define ACPI_DSD_DMA_PROPERTY_NAME "DmaProperty"
34
35/*
36 * Below properties are defined at
37 * https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/power-management-for-storage-hardware-devices-intro
38 */
39#define ACPI_DSD_STORAGE_D3_UUID "5025030F-842F-4AB4-A561-99A5189762D0"
40#define ACPI_DSD_STORAGE_D3_NAME "StorageD3Enable"
41
Duncan Laurie6b7c1f62016-05-09 15:38:36 -070042/* Write empty word value and return pointer to it */
43static void *acpi_device_write_zero_len(void)
44{
45 char *p = acpigen_get_current();
46 acpigen_emit_word(0);
47 return p;
48}
49
50/* Fill in length value from start to current at specified location */
51static void acpi_device_fill_from_len(char *ptr, char *start)
52{
53 uint16_t len = acpigen_get_current() - start;
54 ptr[0] = len & 0xff;
55 ptr[1] = (len >> 8) & 0xff;
56}
57
58/*
59 * Fill in the length field with the value calculated from after
60 * the 16bit field to acpigen current as this length value does
61 * not include the length field itself.
62 */
63static void acpi_device_fill_len(void *ptr)
64{
65 acpi_device_fill_from_len(ptr, ptr + sizeof(uint16_t));
66}
67
Duncan Lauried9af3ce2016-05-08 18:15:25 -070068/* Locate and return the ACPI name for this device */
Aamir Bohrae825d3f2019-07-30 10:11:41 +053069const char *acpi_device_name(const struct device *dev)
Duncan Lauried9af3ce2016-05-08 18:15:25 -070070{
Aamir Bohrae825d3f2019-07-30 10:11:41 +053071 const struct device *pdev = dev;
Duncan Laurie47029142018-05-07 14:28:53 -070072 const char *name = NULL;
73
Duncan Lauried9af3ce2016-05-08 18:15:25 -070074 if (!dev)
75 return NULL;
76
77 /* Check for device specific handler */
CoolStar42be8992023-08-24 02:00:50 -070078 if (dev->ops && dev->ops->acpi_name) {
79 name = dev->ops->acpi_name(dev);
80 if (name)
81 return name;
82 }
Duncan Lauried9af3ce2016-05-08 18:15:25 -070083
Duncan Laurie47029142018-05-07 14:28:53 -070084 /* Walk up the tree to find if any parent can identify this device */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020085 while (pdev->upstream) {
86 pdev = pdev->upstream->dev;
Duncan Laurie47029142018-05-07 14:28:53 -070087 if (!pdev)
88 break;
Patrick Rudolphf95dbce2024-01-22 15:39:46 +010089 if (is_root_device(pdev))
Duncan Laurie47029142018-05-07 14:28:53 -070090 break;
91 if (pdev->ops && pdev->ops->acpi_name)
92 name = pdev->ops->acpi_name(dev);
93 if (name)
94 return name;
95 }
Duncan Lauried9af3ce2016-05-08 18:15:25 -070096
97 return NULL;
98}
99
Patrick Rudolpheeb8e742019-08-20 08:20:01 +0200100/* Locate and return the ACPI _HID (Hardware ID) for this device */
101const char *acpi_device_hid(const struct device *dev)
102{
103 if (!dev)
104 return NULL;
105
106 /* Check for device specific handler */
107 if (dev->ops->acpi_hid)
108 return dev->ops->acpi_hid(dev);
109
110 /*
111 * Don't walk up the tree to find any parent that can identify this device, as
112 * PNP devices are hard to identify.
113 */
114
115 return NULL;
116}
117
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100118/*
119 * Generate unique ID based on the ACPI path.
120 * Collisions on the same _HID are possible but very unlikely.
121 */
Furquan Shaikhd14d03a2020-04-24 21:27:29 -0700122uint32_t acpi_device_uid(const struct device *dev)
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100123{
124 const char *path = acpi_device_path(dev);
125 if (!path)
126 return 0;
127
128 return CRC(path, strlen(path), crc32_byte);
129}
130
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700131/* Recursive function to find the root device and print a path from there */
Aamir Bohrae825d3f2019-07-30 10:11:41 +0530132static ssize_t acpi_device_path_fill(const struct device *dev, char *buf,
Duncan Laurie47029142018-05-07 14:28:53 -0700133 size_t buf_len, size_t cur)
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700134{
135 const char *name = acpi_device_name(dev);
Duncan Laurie47029142018-05-07 14:28:53 -0700136 ssize_t next = 0;
137
138 if (!name)
139 return -1;
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700140
141 /*
142 * Make sure this name segment will fit, including the path segment
143 * separator and possible NUL terminator if this is the last segment.
144 */
Duncan Laurie47029142018-05-07 14:28:53 -0700145 if (!dev || (cur + strlen(name) + 2) > buf_len)
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700146 return cur;
147
148 /* Walk up the tree to the root device */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200149 if (!is_root_device(dev) && dev->upstream && dev->upstream->dev)
150 next = acpi_device_path_fill(dev->upstream->dev, buf, buf_len, cur);
Duncan Laurie47029142018-05-07 14:28:53 -0700151 if (next < 0)
152 return next;
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700153
154 /* Fill in the path from the root device */
155 next += snprintf(buf + next, buf_len - next, "%s%s",
Patrick Rudolphf95dbce2024-01-22 15:39:46 +0100156 (is_root_device(dev) || (strlen(name) == 0)) ?
157 "" : ".", name);
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700158
159 return next;
160}
161
162/*
163 * Warning: just as with dev_path() this uses a static buffer
Martin Roth0949e732021-10-01 14:28:22 -0600164 * so should not be called multiple times in one statement
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700165 */
Aamir Bohrae825d3f2019-07-30 10:11:41 +0530166const char *acpi_device_path(const struct device *dev)
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700167{
168 static char buf[DEVICE_PATH_MAX] = {};
169
170 if (!dev)
171 return NULL;
172
173 if (acpi_device_path_fill(dev, buf, sizeof(buf), 0) <= 0)
174 return NULL;
175
176 return buf;
177}
178
179/* Return the path of the parent device as the ACPI Scope for this device */
Aamir Bohrae825d3f2019-07-30 10:11:41 +0530180const char *acpi_device_scope(const struct device *dev)
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700181{
Duncan Lauried02685b2016-06-30 14:37:37 -0700182 static char buf[DEVICE_PATH_MAX] = {};
183
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200184 if (!dev || !dev->upstream || !dev->upstream->dev)
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700185 return NULL;
186
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200187 if (acpi_device_path_fill(dev->upstream->dev, buf, sizeof(buf), 0) <= 0)
Duncan Lauried02685b2016-06-30 14:37:37 -0700188 return NULL;
189
190 return buf;
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700191}
192
Elyes HAOUAS6716bab2020-01-09 21:29:25 +0100193/* Concatenate the device path and provided name suffix */
Aamir Bohrae825d3f2019-07-30 10:11:41 +0530194const char *acpi_device_path_join(const struct device *dev, const char *name)
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700195{
196 static char buf[DEVICE_PATH_MAX] = {};
Jacob Garberf2ba2d92019-07-02 10:50:10 -0600197 ssize_t len;
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700198
199 if (!dev)
200 return NULL;
201
202 /* Build the path of this device */
203 len = acpi_device_path_fill(dev, buf, sizeof(buf), 0);
204 if (len <= 0)
205 return NULL;
206
207 /* Ensure there is room for the added name, separator, and NUL */
208 if ((len + strlen(name) + 2) > sizeof(buf))
209 return NULL;
210 snprintf(buf + len, sizeof(buf) - len, ".%s", name);
211
212 return buf;
213}
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700214
Hung-Te Linb4be50c2018-09-10 10:55:49 +0800215int acpi_device_status(const struct device *dev)
216{
217 if (!dev->enabled)
218 return ACPI_STATUS_DEVICE_ALL_OFF;
219 if (dev->hidden)
220 return ACPI_STATUS_DEVICE_HIDDEN_ON;
221 return ACPI_STATUS_DEVICE_ALL_ON;
222}
223
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100224/* Write the unique _UID based on ACPI device path. */
Furquan Shaikhd14d03a2020-04-24 21:27:29 -0700225void acpi_device_write_uid(const struct device *dev)
Patrick Rudolphc83bab62019-12-13 12:16:06 +0100226{
227 acpigen_write_name_integer("_UID", acpi_device_uid(dev));
228}
229
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700230/* ACPI 6.1 section 6.4.3.6: Extended Interrupt Descriptor */
231void acpi_device_write_interrupt(const struct acpi_irq *irq)
232{
233 void *desc_length;
234 uint8_t flags;
235
236 if (!irq || !irq->pin)
237 return;
238
239 /* This is supported by GpioInt() but not Interrupt() */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800240 if (irq->polarity == ACPI_IRQ_ACTIVE_BOTH)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700241 return;
242
243 /* Byte 0: Descriptor Type */
244 acpigen_emit_byte(ACPI_DESCRIPTOR_INTERRUPT);
245
246 /* Byte 1-2: Length (filled in later) */
247 desc_length = acpi_device_write_zero_len();
248
249 /*
250 * Byte 3: Flags
251 * [7:5]: Reserved
252 * [4]: Wake (0=NO_WAKE 1=WAKE)
253 * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
254 * [2]: Polarity (0=HIGH 1=LOW)
255 * [1]: Mode (0=LEVEL 1=EDGE)
256 * [0]: Resource (0=PRODUCER 1=CONSUMER)
257 */
258 flags = 1 << 0; /* ResourceConsumer */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800259 if (irq->mode == ACPI_IRQ_EDGE_TRIGGERED)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700260 flags |= 1 << 1;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800261 if (irq->polarity == ACPI_IRQ_ACTIVE_LOW)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700262 flags |= 1 << 2;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800263 if (irq->shared == ACPI_IRQ_SHARED)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700264 flags |= 1 << 3;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800265 if (irq->wake == ACPI_IRQ_WAKE)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700266 flags |= 1 << 4;
267 acpigen_emit_byte(flags);
268
269 /* Byte 4: Interrupt Table Entry Count */
270 acpigen_emit_byte(1);
271
272 /* Byte 5-8: Interrupt Number */
273 acpigen_emit_dword(irq->pin);
274
275 /* Fill in Descriptor Length (account for len word) */
276 acpi_device_fill_len(desc_length);
277}
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700278
279/* ACPI 6.1 section 6.4.3.8.1 - GPIO Interrupt or I/O */
280void acpi_device_write_gpio(const struct acpi_gpio *gpio)
281{
282 void *start, *desc_length;
283 void *pin_table_offset, *vendor_data_offset, *resource_offset;
284 uint16_t flags = 0;
285 int pin;
286
287 if (!gpio || gpio->type > ACPI_GPIO_TYPE_IO)
288 return;
289
290 start = acpigen_get_current();
291
292 /* Byte 0: Descriptor Type */
293 acpigen_emit_byte(ACPI_DESCRIPTOR_GPIO);
294
295 /* Byte 1-2: Length (fill in later) */
296 desc_length = acpi_device_write_zero_len();
297
298 /* Byte 3: Revision ID */
299 acpigen_emit_byte(ACPI_GPIO_REVISION_ID);
300
301 /* Byte 4: GpioIo or GpioInt */
302 acpigen_emit_byte(gpio->type);
303
304 /*
305 * Byte 5-6: General Flags
306 * [15:1]: 0 => Reserved
307 * [0]: 1 => ResourceConsumer
308 */
309 acpigen_emit_word(1 << 0);
310
311 switch (gpio->type) {
312 case ACPI_GPIO_TYPE_INTERRUPT:
313 /*
314 * Byte 7-8: GPIO Interrupt Flags
315 * [15:5]: 0 => Reserved
316 * [4]: Wake (0=NO_WAKE 1=WAKE)
317 * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
318 * [2:1]: Polarity (0=HIGH 1=LOW 2=BOTH)
319 * [0]: Mode (0=LEVEL 1=EDGE)
320 */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800321 if (gpio->irq.mode == ACPI_IRQ_EDGE_TRIGGERED)
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700322 flags |= 1 << 0;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800323 if (gpio->irq.shared == ACPI_IRQ_SHARED)
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700324 flags |= 1 << 3;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800325 if (gpio->irq.wake == ACPI_IRQ_WAKE)
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700326 flags |= 1 << 4;
327
328 switch (gpio->irq.polarity) {
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800329 case ACPI_IRQ_ACTIVE_HIGH:
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700330 flags |= 0 << 1;
331 break;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800332 case ACPI_IRQ_ACTIVE_LOW:
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700333 flags |= 1 << 1;
334 break;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800335 case ACPI_IRQ_ACTIVE_BOTH:
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700336 flags |= 2 << 1;
337 break;
338 }
339 break;
340
341 case ACPI_GPIO_TYPE_IO:
342 /*
343 * Byte 7-8: GPIO IO Flags
344 * [15:4]: 0 => Reserved
345 * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
346 * [2]: 0 => Reserved
347 * [1:0]: IO Restriction
348 * 0 => IoRestrictionNone
349 * 1 => IoRestrictionInputOnly
350 * 2 => IoRestrictionOutputOnly
351 * 3 => IoRestrictionNoneAndPreserve
352 */
353 flags |= gpio->io_restrict & 3;
354 if (gpio->io_shared)
355 flags |= 1 << 3;
356 break;
357 }
358 acpigen_emit_word(flags);
359
360 /*
361 * Byte 9: Pin Configuration
362 * 0x01 => Default (no configuration applied)
363 * 0x02 => Pull-up
364 * 0x03 => Pull-down
365 * 0x04-0x7F => Reserved
366 * 0x80-0xff => Vendor defined
367 */
368 acpigen_emit_byte(gpio->pull);
369
370 /* Byte 10-11: Output Drive Strength in 1/100 mA */
371 acpigen_emit_word(gpio->output_drive_strength);
372
373 /* Byte 12-13: Debounce Timeout in 1/100 ms */
374 acpigen_emit_word(gpio->interrupt_debounce_timeout);
375
376 /* Byte 14-15: Pin Table Offset, relative to start */
377 pin_table_offset = acpi_device_write_zero_len();
378
379 /* Byte 16: Reserved */
380 acpigen_emit_byte(0);
381
382 /* Byte 17-18: Resource Source Name Offset, relative to start */
383 resource_offset = acpi_device_write_zero_len();
384
385 /* Byte 19-20: Vendor Data Offset, relative to start */
386 vendor_data_offset = acpi_device_write_zero_len();
387
388 /* Byte 21-22: Vendor Data Length */
389 acpigen_emit_word(0);
390
391 /* Fill in Pin Table Offset */
392 acpi_device_fill_from_len(pin_table_offset, start);
393
394 /* Pin Table, one word for each pin */
Duncan Laurie5b6c28c2016-06-29 10:47:22 -0700395 for (pin = 0; pin < gpio->pin_count; pin++) {
396 uint16_t acpi_pin = gpio->pins[pin];
Julius Wernercd49cce2019-03-05 16:53:33 -0800397#if CONFIG(GENERIC_GPIO_LIB)
Duncan Laurie5b6c28c2016-06-29 10:47:22 -0700398 acpi_pin = gpio_acpi_pin(acpi_pin);
399#endif
400 acpigen_emit_word(acpi_pin);
401 }
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700402
403 /* Fill in Resource Source Name Offset */
404 acpi_device_fill_from_len(resource_offset, start);
405
406 /* Resource Source Name String */
Julius Wernercd49cce2019-03-05 16:53:33 -0800407#if CONFIG(GENERIC_GPIO_LIB)
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700408 acpigen_emit_string(gpio->resource ? : gpio_acpi_path(gpio->pins[0]));
409#else
410 acpigen_emit_string(gpio->resource);
411#endif
412
413 /* Fill in Vendor Data Offset */
414 acpi_device_fill_from_len(vendor_data_offset, start);
415
416 /* Fill in GPIO Descriptor Length (account for len word) */
417 acpi_device_fill_len(desc_length);
418}
Duncan Laurie1010b4a2016-05-09 20:10:47 -0700419
420/* ACPI 6.1 section 6.4.3.8.2.1 - I2cSerialBus() */
421void acpi_device_write_i2c(const struct acpi_i2c *i2c)
422{
423 void *desc_length, *type_length;
424
425 /* Byte 0: Descriptor Type */
426 acpigen_emit_byte(ACPI_DESCRIPTOR_SERIAL_BUS);
427
428 /* Byte 1+2: Length (filled in later) */
429 desc_length = acpi_device_write_zero_len();
430
431 /* Byte 3: Revision ID */
Elyes HAOUAS34564ed2019-04-16 08:12:10 +0200432 acpigen_emit_byte(ACPI_I2C_SERIAL_BUS_REVISION_ID);
Duncan Laurie1010b4a2016-05-09 20:10:47 -0700433
434 /* Byte 4: Resource Source Index is Reserved */
435 acpigen_emit_byte(0);
436
437 /* Byte 5: Serial Bus Type is I2C */
438 acpigen_emit_byte(ACPI_SERIAL_BUS_TYPE_I2C);
439
440 /*
441 * Byte 6: Flags
442 * [7:2]: 0 => Reserved
443 * [1]: 1 => ResourceConsumer
444 * [0]: 0 => ControllerInitiated
445 */
446 acpigen_emit_byte(1 << 1);
447
448 /*
449 * Byte 7-8: Type Specific Flags
450 * [15:1]: 0 => Reserved
451 * [0]: 0 => 7bit, 1 => 10bit
452 */
453 acpigen_emit_word(i2c->mode_10bit);
454
455 /* Byte 9: Type Specific Revision ID */
Elyes HAOUAS34564ed2019-04-16 08:12:10 +0200456 acpigen_emit_byte(ACPI_I2C_TYPE_SPECIFIC_REVISION_ID);
Duncan Laurie1010b4a2016-05-09 20:10:47 -0700457
458 /* Byte 10-11: I2C Type Data Length */
459 type_length = acpi_device_write_zero_len();
460
461 /* Byte 12-15: I2C Bus Speed */
462 acpigen_emit_dword(i2c->speed);
463
464 /* Byte 16-17: I2C Slave Address */
465 acpigen_emit_word(i2c->address);
466
467 /* Fill in Type Data Length */
468 acpi_device_fill_len(type_length);
469
470 /* Byte 18+: ResourceSource */
471 acpigen_emit_string(i2c->resource);
472
473 /* Fill in I2C Descriptor Length */
474 acpi_device_fill_len(desc_length);
475}
Duncan Laurie70c86d92016-05-10 07:26:34 -0700476
477/* ACPI 6.1 section 6.4.3.8.2.2 - SpiSerialBus() */
478void acpi_device_write_spi(const struct acpi_spi *spi)
479{
480 void *desc_length, *type_length;
481 uint16_t flags = 0;
482
483 /* Byte 0: Descriptor Type */
484 acpigen_emit_byte(ACPI_DESCRIPTOR_SERIAL_BUS);
485
486 /* Byte 1+2: Length (filled in later) */
487 desc_length = acpi_device_write_zero_len();
488
489 /* Byte 3: Revision ID */
Elyes HAOUAS34564ed2019-04-16 08:12:10 +0200490 acpigen_emit_byte(ACPI_SPI_SERIAL_BUS_REVISION_ID);
Duncan Laurie70c86d92016-05-10 07:26:34 -0700491
492 /* Byte 4: Resource Source Index is Reserved */
493 acpigen_emit_byte(0);
494
495 /* Byte 5: Serial Bus Type is SPI */
496 acpigen_emit_byte(ACPI_SERIAL_BUS_TYPE_SPI);
497
498 /*
499 * Byte 6: Flags
500 * [7:2]: 0 => Reserved
501 * [1]: 1 => ResourceConsumer
502 * [0]: 0 => ControllerInitiated
503 */
504 acpigen_emit_byte(1 << 1);
505
506 /*
507 * Byte 7-8: Type Specific Flags
508 * [15:2]: 0 => Reserved
509 * [1]: 0 => ActiveLow, 1 => ActiveHigh
510 * [0]: 0 => FourWire, 1 => ThreeWire
511 */
512 if (spi->wire_mode == SPI_3_WIRE_MODE)
513 flags |= 1 << 0;
514 if (spi->device_select_polarity == SPI_POLARITY_HIGH)
515 flags |= 1 << 1;
516 acpigen_emit_word(flags);
517
518 /* Byte 9: Type Specific Revision ID */
Elyes HAOUAS34564ed2019-04-16 08:12:10 +0200519 acpigen_emit_byte(ACPI_SPI_TYPE_SPECIFIC_REVISION_ID);
Duncan Laurie70c86d92016-05-10 07:26:34 -0700520
521 /* Byte 10-11: SPI Type Data Length */
522 type_length = acpi_device_write_zero_len();
523
524 /* Byte 12-15: Connection Speed */
525 acpigen_emit_dword(spi->speed);
526
527 /* Byte 16: Data Bit Length */
528 acpigen_emit_byte(spi->data_bit_length);
529
530 /* Byte 17: Clock Phase */
531 acpigen_emit_byte(spi->clock_phase);
532
533 /* Byte 18: Clock Polarity */
534 acpigen_emit_byte(spi->clock_polarity);
535
536 /* Byte 19-20: Device Selection */
537 acpigen_emit_word(spi->device_select);
538
539 /* Fill in Type Data Length */
540 acpi_device_fill_len(type_length);
541
542 /* Byte 21+: ResourceSource String */
543 acpigen_emit_string(spi->resource);
544
545 /* Fill in SPI Descriptor Length */
546 acpi_device_fill_len(desc_length);
547}
Duncan Laurie559e9472016-05-10 13:18:17 -0700548
Duncan Lauriedccef0d2020-05-27 12:29:51 -0700549/* UART Serial Bus - UARTSerialBusV2() */
550void acpi_device_write_uart(const struct acpi_uart *uart)
551{
552 void *desc_length, *type_length;
553 uint16_t flags;
554
555 /* Byte 0: Descriptor Type */
556 acpigen_emit_byte(ACPI_DESCRIPTOR_SERIAL_BUS);
557
558 /* Byte 1+2: Length (filled in later) */
559 desc_length = acpi_device_write_zero_len();
560
561 /* Byte 3: Revision ID */
562 acpigen_emit_byte(ACPI_UART_SERIAL_BUS_REVISION_ID);
563
564 /* Byte 4: Resource Source Index is Reserved */
565 acpigen_emit_byte(0);
566
567 /* Byte 5: Serial Bus Type is UART */
568 acpigen_emit_byte(ACPI_SERIAL_BUS_TYPE_UART);
569
570 /*
571 * Byte 6: Flags
572 * [7:2]: 0 => Reserved
573 * [1]: 1 => ResourceConsumer
574 * [0]: 0 => ControllerInitiated
575 */
576 acpigen_emit_byte(BIT(1));
577
578 /*
579 * Byte 7-8: Type Specific Flags
580 * [15:8]: 0 => Reserved
581 * [7]: 0 => Little Endian, 1 => Big Endian
582 * [6:4]: Data bits
583 * [3:2]: Stop bits
584 * [1:0]: Flow control
585 */
586 flags = uart->flow_control & 3;
587 flags |= (uart->stop_bits & 3) << 2;
588 flags |= (uart->data_bits & 7) << 4;
589 flags |= (uart->endian & 1) << 7;
590 acpigen_emit_word(flags);
591
592 /* Byte 9: Type Specific Revision ID */
593 acpigen_emit_byte(ACPI_UART_TYPE_SPECIFIC_REVISION_ID);
594
595 /* Byte 10-11: Type Data Length */
596 type_length = acpi_device_write_zero_len();
597
598 /* Byte 12-15: Initial Baud Rate */
599 acpigen_emit_dword(uart->initial_baud_rate);
600
601 /* Byte 16-17: RX FIFO size */
602 acpigen_emit_word(uart->rx_fifo_bytes);
603
604 /* Byte 18-19: TX FIFO size */
605 acpigen_emit_word(uart->tx_fifo_bytes);
606
607 /* Byte 20: Parity */
608 acpigen_emit_byte(uart->parity);
609
610 /* Byte 21: Lines Enabled */
611 acpigen_emit_byte(uart->lines_in_use);
612
613 /* Fill in Type Data Length */
614 acpi_device_fill_len(type_length);
615
616 /* Byte 22+: ResourceSource */
617 acpigen_emit_string(uart->resource);
618
619 /* Fill in Descriptor Length */
620 acpi_device_fill_len(desc_length);
621}
622
Raul E Rangel6d2bc002021-05-27 15:04:21 -0600623#define ACPI_POWER_RESOURCE_STATUS_ON_OP ONE_OP
624#define ACPI_POWER_RESOURCE_STATUS_OFF_OP ZERO_OP
625
626/**
627 * Writes an ACPI fragment that will check the GPIO and return 0 if the GPIO
628 * state does not match the active parameter.
629 */
630static void acpigen_write_gpio_STA(const struct acpi_gpio *gpio, bool active)
631{
632 if (!gpio || !gpio->pin_count)
633 return;
634
635 /* Read current GPIO status into Local0. */
636 acpigen_get_tx_gpio(gpio);
637
638 /*
639 * If (!Local0)
640 * {
641 * Return (Zero)
642 * }
643 */
644 acpigen_write_if();
645 if (active)
646 acpigen_emit_byte(LNOT_OP);
647 acpigen_emit_byte(LOCAL0_OP);
648 acpigen_write_return_op(ACPI_POWER_RESOURCE_STATUS_OFF_OP);
649 acpigen_write_if_end();
650}
651
652static void acpigen_write_power_res_STA(const struct acpi_power_res_params *params)
653{
654 acpigen_write_method_serialized("_STA", 0);
655
656 /* Verify all the GPIOs are in the ON state, otherwise return 0 */
657 acpigen_write_gpio_STA(params->enable_gpio, true);
658 acpigen_write_gpio_STA(params->reset_gpio, false);
659 acpigen_write_gpio_STA(params->stop_gpio, false);
660
661 /* All GPIOs are in the ON state */
662 acpigen_write_return_op(ACPI_POWER_RESOURCE_STATUS_ON_OP);
663
664 acpigen_pop_len(); /* Method */
665}
666
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800667/* PowerResource() with Enable and/or Reset control */
Shelley Chena0603392018-04-26 13:52:30 -0700668void acpi_device_add_power_res(const struct acpi_power_res_params *params)
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800669{
Furquan Shaikhd47946e2021-09-14 15:54:41 -0700670 static uint8_t id;
Furquan Shaikhdc782752020-04-30 22:49:39 -0700671 static const char * const power_res_dev_states[] = { "_PR0", "_PR3" };
Edward O'Callaghan7e262552020-01-23 10:32:33 +1100672 unsigned int reset_gpio = params->reset_gpio ? params->reset_gpio->pins[0] : 0;
673 unsigned int enable_gpio = params->enable_gpio ? params->enable_gpio->pins[0] : 0;
674 unsigned int stop_gpio = params->stop_gpio ? params->stop_gpio->pins[0] : 0;
Furquan Shaikhd47946e2021-09-14 15:54:41 -0700675 char pr_name[ACPI_NAME_BUFFER_SIZE];
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800676
Furquan Shaikhedf459f2017-08-28 17:20:49 -0700677 if (!reset_gpio && !enable_gpio && !stop_gpio)
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800678 return;
679
Furquan Shaikhd47946e2021-09-14 15:54:41 -0700680 snprintf(pr_name, sizeof(pr_name), "PR%02X", id++);
681
682 /* PowerResource (PR##, 0, 0) */
683 acpigen_write_power_res(pr_name, 0, 0, power_res_dev_states,
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800684 ARRAY_SIZE(power_res_dev_states));
685
Raul E Rangel6d2bc002021-05-27 15:04:21 -0600686 if (params->use_gpio_for_status) {
687 acpigen_write_power_res_STA(params);
688 } else {
689 /* Method (_STA, 0, NotSerialized) { Return (0x1) } */
690 acpigen_write_STA(ACPI_POWER_RESOURCE_STATUS_ON_OP);
691 }
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800692
693 /* Method (_ON, 0, Serialized) */
694 acpigen_write_method_serialized("_ON", 0);
Tim Van Patten3d4665c2022-04-13 11:53:20 -0600695 /* Call _STA and early return if the device is already enabled, since the Linux
696 kernel doesn't check the device status before calling _ON. This avoids
697 unnecessary delays while booting. */
698 if (params->use_gpio_for_status) {
699 /* Local0 = _STA () */
700 acpigen_write_store();
701 acpigen_emit_namestring("_STA");
702 acpigen_emit_byte(LOCAL0_OP);
703 /* If (( Local0 == ACPI_POWER_RESOURCE_STATUS_ON_OP)) */
704 acpigen_write_if_lequal_op_op(LOCAL0_OP, ACPI_POWER_RESOURCE_STATUS_ON_OP);
705 acpigen_write_return_op(ZERO_OP);
706 acpigen_write_if_end();
707 }
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800708 if (reset_gpio)
Shelley Chena0603392018-04-26 13:52:30 -0700709 acpigen_enable_tx_gpio(params->reset_gpio);
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800710 if (enable_gpio) {
Shelley Chena0603392018-04-26 13:52:30 -0700711 acpigen_enable_tx_gpio(params->enable_gpio);
712 if (params->enable_delay_ms)
713 acpigen_write_sleep(params->enable_delay_ms);
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800714 }
715 if (reset_gpio) {
Shelley Chena0603392018-04-26 13:52:30 -0700716 acpigen_disable_tx_gpio(params->reset_gpio);
717 if (params->reset_delay_ms)
718 acpigen_write_sleep(params->reset_delay_ms);
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800719 }
Furquan Shaikhedf459f2017-08-28 17:20:49 -0700720 if (stop_gpio) {
Shelley Chena0603392018-04-26 13:52:30 -0700721 acpigen_disable_tx_gpio(params->stop_gpio);
722 if (params->stop_delay_ms)
723 acpigen_write_sleep(params->stop_delay_ms);
Furquan Shaikhedf459f2017-08-28 17:20:49 -0700724 }
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800725 acpigen_pop_len(); /* _ON method */
726
727 /* Method (_OFF, 0, Serialized) */
728 acpigen_write_method_serialized("_OFF", 0);
Shelley Chena0603392018-04-26 13:52:30 -0700729 if (stop_gpio) {
730 acpigen_enable_tx_gpio(params->stop_gpio);
731 if (params->stop_off_delay_ms)
732 acpigen_write_sleep(params->stop_off_delay_ms);
733 }
734 if (reset_gpio) {
735 acpigen_enable_tx_gpio(params->reset_gpio);
736 if (params->reset_off_delay_ms)
737 acpigen_write_sleep(params->reset_off_delay_ms);
738 }
739 if (enable_gpio) {
740 acpigen_disable_tx_gpio(params->enable_gpio);
741 if (params->enable_off_delay_ms)
742 acpigen_write_sleep(params->enable_off_delay_ms);
743 }
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800744 acpigen_pop_len(); /* _OFF method */
745
Furquan Shaikhd47946e2021-09-14 15:54:41 -0700746 acpigen_pop_len(); /* PowerResource PR## */
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800747}
748
Duncan Laurieffc99902016-07-02 19:56:06 -0700749static void acpi_dp_write_array(const struct acpi_dp *array);
750static void acpi_dp_write_value(const struct acpi_dp *prop)
Duncan Laurie559e9472016-05-10 13:18:17 -0700751{
752 switch (prop->type) {
753 case ACPI_DP_TYPE_INTEGER:
754 acpigen_write_integer(prop->integer);
755 break;
756 case ACPI_DP_TYPE_STRING:
Harsha Priya3a96ac42016-07-15 17:31:43 -0700757 case ACPI_DP_TYPE_CHILD:
Duncan Laurie559e9472016-05-10 13:18:17 -0700758 acpigen_write_string(prop->string);
759 break;
760 case ACPI_DP_TYPE_REFERENCE:
761 acpigen_emit_namestring(prop->string);
762 break;
Duncan Laurieffc99902016-07-02 19:56:06 -0700763 case ACPI_DP_TYPE_ARRAY:
764 acpi_dp_write_array(prop->array);
765 break;
766 default:
767 break;
Duncan Laurie559e9472016-05-10 13:18:17 -0700768 }
769}
770
Duncan Laurieffc99902016-07-02 19:56:06 -0700771/* Package (2) { "prop->name", VALUE } */
772static void acpi_dp_write_property(const struct acpi_dp *prop)
Duncan Laurie559e9472016-05-10 13:18:17 -0700773{
774 acpigen_write_package(2);
Duncan Laurieffc99902016-07-02 19:56:06 -0700775 acpigen_write_string(prop->name);
Duncan Laurie559e9472016-05-10 13:18:17 -0700776 acpi_dp_write_value(prop);
777 acpigen_pop_len();
Duncan Laurie559e9472016-05-10 13:18:17 -0700778}
779
780/* Write array of Device Properties */
Duncan Laurieffc99902016-07-02 19:56:06 -0700781static void acpi_dp_write_array(const struct acpi_dp *array)
Duncan Laurie559e9472016-05-10 13:18:17 -0700782{
Duncan Laurieffc99902016-07-02 19:56:06 -0700783 const struct acpi_dp *dp;
784 char *pkg_count;
785
786 /* Package element count determined as it is populated */
787 pkg_count = acpigen_write_package(0);
788
Furquan Shaikh35c01bc2016-10-03 23:30:14 -0700789 /*
790 * Only acpi_dp of type DP_TYPE_TABLE is allowed to be an array.
791 * DP_TYPE_TABLE does not have a value to be written. Thus, start
792 * the loop from next type in the array.
793 */
794 for (dp = array->next; dp; dp = dp->next) {
Duncan Laurieffc99902016-07-02 19:56:06 -0700795 acpi_dp_write_value(dp);
796 (*pkg_count)++;
797 }
798
Duncan Laurie559e9472016-05-10 13:18:17 -0700799 acpigen_pop_len();
Duncan Laurie559e9472016-05-10 13:18:17 -0700800}
801
Duncan Laurieffc99902016-07-02 19:56:06 -0700802static void acpi_dp_free(struct acpi_dp *dp)
Duncan Laurie559e9472016-05-10 13:18:17 -0700803{
Duncan Laurieffc99902016-07-02 19:56:06 -0700804 while (dp) {
805 struct acpi_dp *p = dp->next;
806
807 switch (dp->type) {
808 case ACPI_DP_TYPE_CHILD:
809 acpi_dp_free(dp->child);
810 break;
811 case ACPI_DP_TYPE_ARRAY:
812 acpi_dp_free(dp->array);
813 break;
814 default:
815 break;
816 }
817
818 free(dp);
819 dp = p;
820 }
Duncan Laurie559e9472016-05-10 13:18:17 -0700821}
822
Duncan Laurie84fac412020-06-03 12:36:51 -0700823static bool acpi_dp_write_properties(struct acpi_dp *prop, const char *uuid)
824{
825 struct acpi_dp *dp;
826 char *prop_count = NULL;
827
828 /* Print base properties */
829 for (dp = prop; dp; dp = dp->next) {
830 if (dp->type == ACPI_DP_TYPE_TABLE ||
831 dp->type == ACPI_DP_TYPE_CHILD ||
832 dp->type == ACPI_DP_TYPE_PACKAGE)
833 continue;
834
835 /*
836 * The UUID and package is only added when
837 * we come across the first property. This
838 * is to avoid creating a zero-length package
839 * in situations where there are only children.
840 */
841 if (!prop_count) {
842 /* ToUUID (dp->uuid) */
843 acpigen_write_uuid(uuid);
844 /*
845 * Package (PROP), element count determined as
846 * it is populated
847 */
848 prop_count = acpigen_write_package(0);
849 }
850 (*prop_count)++;
851 acpi_dp_write_property(dp);
852 }
853 if (prop_count) {
854 /* Package (PROP) length, if a package was written */
855 acpigen_pop_len();
856 return true;
857 }
858 return false;
859}
860
Simon Glass8bfa51e2020-06-29 16:18:37 -0600861static void acpi_dp_write_(struct acpi_dp *table)
Duncan Laurie559e9472016-05-10 13:18:17 -0700862{
Duncan Laurieffc99902016-07-02 19:56:06 -0700863 struct acpi_dp *dp, *prop;
Duncan Laurie84fac412020-06-03 12:36:51 -0700864 char *dp_count;
Duncan Laurieffc99902016-07-02 19:56:06 -0700865 int child_count = 0;
866
Duncan Lauriec1adeb62020-04-29 00:04:14 -0700867 if (!table || table->type != ACPI_DP_TYPE_TABLE || !table->next)
Duncan Laurieffc99902016-07-02 19:56:06 -0700868 return;
869
870 /* Name (name) */
871 acpigen_write_name(table->name);
872
873 /* Device Property list starts with the next entry */
874 prop = table->next;
875
Matt Delco08258882019-01-30 11:16:08 -0800876 /* Package (DP), default to assuming no properties or children */
877 dp_count = acpigen_write_package(0);
Duncan Laurieffc99902016-07-02 19:56:06 -0700878
879 /* Print base properties */
Duncan Laurie84fac412020-06-03 12:36:51 -0700880 if (acpi_dp_write_properties(prop, table->uuid))
881 *dp_count += 2;
Duncan Laurieffc99902016-07-02 19:56:06 -0700882
Duncan Laurie84fac412020-06-03 12:36:51 -0700883 /* Count child properties */
884 for (dp = prop; dp; dp = dp->next)
885 if (dp->type == ACPI_DP_TYPE_CHILD)
886 child_count++;
887
888 /* Add child properties to the base table */
Duncan Laurieffc99902016-07-02 19:56:06 -0700889 if (child_count) {
Duncan Laurie84fac412020-06-03 12:36:51 -0700890 /* Update DP package count */
Matt Delco08258882019-01-30 11:16:08 -0800891 *dp_count += 2;
Duncan Laurieffc99902016-07-02 19:56:06 -0700892 /* ToUUID (ACPI_DP_CHILD_UUID) */
893 acpigen_write_uuid(ACPI_DP_CHILD_UUID);
894
895 /* Print child pointer properties */
896 acpigen_write_package(child_count);
897
898 for (dp = prop; dp; dp = dp->next)
899 if (dp->type == ACPI_DP_TYPE_CHILD)
900 acpi_dp_write_property(dp);
Matt Delco08258882019-01-30 11:16:08 -0800901 /* Package (CHILD) length */
Duncan Laurieffc99902016-07-02 19:56:06 -0700902 acpigen_pop_len();
903 }
904
Duncan Laurie84fac412020-06-03 12:36:51 -0700905 /* Write packages of properties with unique UUID */
906 for (dp = prop; dp; dp = dp->next)
907 if (dp->type == ACPI_DP_TYPE_PACKAGE)
908 if (acpi_dp_write_properties(dp->child, dp->uuid))
909 *dp_count += 2;
910
Duncan Laurieffc99902016-07-02 19:56:06 -0700911 /* Package (DP) length */
912 acpigen_pop_len();
913
914 /* Recursively parse children into separate tables */
915 for (dp = prop; dp; dp = dp->next)
916 if (dp->type == ACPI_DP_TYPE_CHILD)
Simon Glass8bfa51e2020-06-29 16:18:37 -0600917 acpi_dp_write_(dp->child);
918}
919
920void acpi_dp_write(struct acpi_dp *table)
921{
922 acpi_dp_write_(table);
Duncan Laurieffc99902016-07-02 19:56:06 -0700923
924 /* Clean up */
925 acpi_dp_free(table);
926}
927
928static struct acpi_dp *acpi_dp_new(struct acpi_dp *dp, enum acpi_dp_type type,
929 const char *name)
930{
931 struct acpi_dp *new;
932
933 new = malloc(sizeof(struct acpi_dp));
934 if (!new)
935 return NULL;
936
937 memset(new, 0, sizeof(*new));
938 new->type = type;
939 new->name = name;
Duncan Laurie84fac412020-06-03 12:36:51 -0700940 new->uuid = ACPI_DP_UUID;
Duncan Laurieffc99902016-07-02 19:56:06 -0700941
942 if (dp) {
943 /* Add to end of property list */
944 while (dp->next)
945 dp = dp->next;
946 dp->next = new;
947 }
948
949 return new;
950}
951
952struct acpi_dp *acpi_dp_new_table(const char *name)
953{
954 return acpi_dp_new(NULL, ACPI_DP_TYPE_TABLE, name);
955}
956
Duncan Laurieb3023b62017-08-29 08:26:50 -0700957size_t acpi_dp_add_property_list(struct acpi_dp *dp,
958 const struct acpi_dp *property_list,
959 size_t property_count)
960{
961 const struct acpi_dp *prop;
962 size_t i, properties_added = 0;
963
Jacob Garberc30e5902019-05-23 14:34:58 -0600964 if (!dp || !property_list)
965 return 0;
966
Duncan Laurieb3023b62017-08-29 08:26:50 -0700967 for (i = 0; i < property_count; i++) {
968 prop = &property_list[i];
969
970 if (prop->type == ACPI_DP_TYPE_UNKNOWN || !prop->name)
971 continue;
972
973 switch (prop->type) {
974 case ACPI_DP_TYPE_INTEGER:
975 acpi_dp_add_integer(dp, prop->name, prop->integer);
976 break;
977 case ACPI_DP_TYPE_STRING:
978 acpi_dp_add_string(dp, prop->name, prop->string);
979 break;
980 case ACPI_DP_TYPE_REFERENCE:
981 acpi_dp_add_reference(dp, prop->name, prop->string);
982 break;
983 case ACPI_DP_TYPE_ARRAY:
984 acpi_dp_add_array(dp, prop->array);
985 break;
986 case ACPI_DP_TYPE_CHILD:
987 acpi_dp_add_child(dp, prop->name, prop->child);
988 break;
989 default:
990 continue;
991 }
992
993 ++properties_added;
994 }
995
996 return properties_added;
997}
998
Duncan Laurieffc99902016-07-02 19:56:06 -0700999struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
1000 uint64_t value)
1001{
Jacob Garberc30e5902019-05-23 14:34:58 -06001002 if (!dp)
1003 return NULL;
1004
Duncan Laurieffc99902016-07-02 19:56:06 -07001005 struct acpi_dp *new = acpi_dp_new(dp, ACPI_DP_TYPE_INTEGER, name);
1006
1007 if (new)
1008 new->integer = value;
1009
1010 return new;
1011}
1012
1013struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
1014 const char *string)
1015{
Jacob Garberc30e5902019-05-23 14:34:58 -06001016 if (!dp)
1017 return NULL;
1018
Duncan Laurieffc99902016-07-02 19:56:06 -07001019 struct acpi_dp *new = acpi_dp_new(dp, ACPI_DP_TYPE_STRING, name);
1020
1021 if (new)
1022 new->string = string;
1023
1024 return new;
1025}
1026
1027struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
1028 const char *reference)
1029{
Jacob Garberc30e5902019-05-23 14:34:58 -06001030 if (!dp)
1031 return NULL;
1032
Duncan Laurieffc99902016-07-02 19:56:06 -07001033 struct acpi_dp *new = acpi_dp_new(dp, ACPI_DP_TYPE_REFERENCE, name);
1034
1035 if (new)
1036 new->string = reference;
1037
1038 return new;
1039}
1040
1041struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
1042 struct acpi_dp *child)
1043{
1044 struct acpi_dp *new;
1045
Jacob Garberc30e5902019-05-23 14:34:58 -06001046 if (!dp || !child || child->type != ACPI_DP_TYPE_TABLE)
Duncan Laurieffc99902016-07-02 19:56:06 -07001047 return NULL;
1048
1049 new = acpi_dp_new(dp, ACPI_DP_TYPE_CHILD, name);
1050 if (new) {
1051 new->child = child;
1052 new->string = child->name;
1053 }
1054
1055 return new;
1056}
1057
Duncan Laurie84fac412020-06-03 12:36:51 -07001058struct acpi_dp *acpi_dp_add_package(struct acpi_dp *dp, struct acpi_dp *package)
1059{
1060 struct acpi_dp *new;
1061
1062 if (!dp || !package || package->type != ACPI_DP_TYPE_TABLE)
1063 return NULL;
1064
1065 new = acpi_dp_new(dp, ACPI_DP_TYPE_PACKAGE, NULL);
1066 if (new) {
1067 new->uuid = package->name;
1068 new->child = package;
1069 }
1070
1071 return new;
1072}
1073
Duncan Laurieffc99902016-07-02 19:56:06 -07001074struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array)
1075{
1076 struct acpi_dp *new;
1077
Jacob Garberc30e5902019-05-23 14:34:58 -06001078 if (!dp || !array || array->type != ACPI_DP_TYPE_TABLE)
Duncan Laurieffc99902016-07-02 19:56:06 -07001079 return NULL;
1080
1081 new = acpi_dp_new(dp, ACPI_DP_TYPE_ARRAY, array->name);
1082 if (new)
1083 new->array = array;
1084
1085 return new;
1086}
1087
1088struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
Duncan Laurieed6eb272020-04-29 11:39:08 -07001089 const uint64_t *array, int len)
Duncan Laurieffc99902016-07-02 19:56:06 -07001090{
1091 struct acpi_dp *dp_array;
1092 int i;
1093
Jacob Garberc30e5902019-05-23 14:34:58 -06001094 if (!dp || len <= 0)
Duncan Laurieffc99902016-07-02 19:56:06 -07001095 return NULL;
1096
1097 dp_array = acpi_dp_new_table(name);
1098 if (!dp_array)
1099 return NULL;
1100
1101 for (i = 0; i < len; i++)
1102 if (!acpi_dp_add_integer(dp_array, NULL, array[i]))
1103 break;
1104
1105 acpi_dp_add_array(dp, dp_array);
1106
1107 return dp_array;
1108}
1109
Karthikeyan Ramasubramanian685dbe12020-10-05 10:44:50 -06001110struct acpi_dp *acpi_dp_add_gpio_array(struct acpi_dp *dp, const char *name,
1111 const struct acpi_gpio_res_params *params,
1112 size_t param_count)
1113{
1114 struct acpi_dp *gpio;
1115 uint32_t i;
1116
1117 if (!dp || !param_count)
1118 return NULL;
1119
1120 gpio = acpi_dp_new_table(name);
1121 if (!gpio)
1122 return NULL;
1123
1124 /*
1125 * Generate ACPI identifiers as follows:
1126 * Package () {
1127 * name, // e.g. cs-gpios
1128 * Package() {
1129 * ref, index, pin, active_low, // GPIO-0 (params[0])
1130 * ref, index, pin, active_low, // GPIO-1 (params[1])
1131 * ...
1132 * }
1133 * }
1134 */
1135 for (i = 0; i < param_count; i++, params++) {
1136 /*
1137 * If refs is NULL, leave a hole in the gpio array. This can be used in
1138 * conditions where some controllers use both GPIOs and native signals.
1139 */
1140 if (!params->ref) {
1141 acpi_dp_add_integer(gpio, NULL, 0);
1142 continue;
1143 }
1144
1145 /* The device that has _CRS containing GpioIO()/GpioInt() */
1146 acpi_dp_add_reference(gpio, NULL, params->ref);
1147
1148 /* Index of the GPIO resource in _CRS starting from zero */
1149 acpi_dp_add_integer(gpio, NULL, params->index);
1150
1151 /* Pin in the GPIO resource, typically zero */
1152 acpi_dp_add_integer(gpio, NULL, params->pin);
1153
1154 /* Set if pin is active low */
1155 acpi_dp_add_integer(gpio, NULL, params->active_low);
1156 }
1157 acpi_dp_add_array(dp, gpio);
1158
1159 return gpio;
Karthikeyan Ramasubramanian685dbe12020-10-05 10:44:50 -06001160}
1161
1162
Duncan Laurieffc99902016-07-02 19:56:06 -07001163struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
1164 const char *ref, int index, int pin,
1165 int active_low)
1166{
Karthikeyan Ramasubramanian685dbe12020-10-05 10:44:50 -06001167 struct acpi_gpio_res_params param = {
1168 .ref = ref,
1169 .index = index,
1170 .pin = pin,
1171 .active_low = active_low,
1172 };
Jacob Garberc30e5902019-05-23 14:34:58 -06001173
Karthikeyan Ramasubramanian685dbe12020-10-05 10:44:50 -06001174 return acpi_dp_add_gpio_array(dp, name, &param, 1);
Duncan Laurie559e9472016-05-10 13:18:17 -07001175}
Furquan Shaikhd1130af2020-04-23 12:51:42 -07001176
1177/*
1178 * This function writes a PCI device with _ADR object:
1179 * Example:
1180 * Scope (\_SB.PCI0)
1181 * {
1182 * Device (IGFX)
1183 * {
1184 * Name (_ADR, 0x0000000000000000)
1185 * Method (_STA, 0, NotSerialized) { Return (status) }
1186 * }
1187 * }
1188 */
Furquan Shaikh7536a392020-04-24 21:59:21 -07001189void acpi_device_write_pci_dev(const struct device *dev)
Furquan Shaikhd1130af2020-04-23 12:51:42 -07001190{
1191 const char *scope = acpi_device_scope(dev);
1192 const char *name = acpi_device_name(dev);
1193
1194 assert(dev->path.type == DEVICE_PATH_PCI);
1195 assert(name);
1196 assert(scope);
1197
1198 acpigen_write_scope(scope);
1199 acpigen_write_device(name);
1200
1201 acpigen_write_ADR_pci_device(dev);
1202 acpigen_write_STA(acpi_device_status(dev));
1203
1204 acpigen_pop_len(); /* Device */
1205 acpigen_pop_len(); /* Scope */
1206}
Kapil Porwalddc52a62022-11-26 19:10:57 +05301207
Kapil Porwal75436272022-11-28 17:25:48 +05301208/*
1209 * Helper function to add given integer property with an UUID to _DSD in the current scope.
1210 *
1211 * dsd - Pointer to a _DSD object.
1212 * Append to existing _DSD object if not NULL.
1213 * Create new _DSD object and flush it if NULL.
1214 * uuid - Pointer to the UUID string.
1215 * name - Pointer to the property name string.
1216 * value - Value of the integer property.
1217 */
1218static void acpi_device_add_integer_property_with_uuid(struct acpi_dp *dsd,
1219 const char *uuid,
1220 const char *name,
1221 uint64_t value)
Kapil Porwalddc52a62022-11-26 19:10:57 +05301222{
1223 struct acpi_dp *prev_dsd = dsd, *pkg;
1224 if (prev_dsd == NULL)
1225 dsd = acpi_dp_new_table("_DSD");
Kapil Porwal75436272022-11-28 17:25:48 +05301226 pkg = acpi_dp_new_table(uuid);
1227 acpi_dp_add_integer(pkg, name, value);
Kapil Porwalddc52a62022-11-26 19:10:57 +05301228 acpi_dp_add_package(dsd, pkg);
1229 if (prev_dsd == NULL)
1230 acpi_dp_write(dsd);
1231}
Kapil Porwal75436272022-11-28 17:25:48 +05301232
1233/* _DSD with ExternalFacingPort */
1234void acpi_device_add_external_facing_port(struct acpi_dp *dsd)
1235{
1236 acpi_device_add_integer_property_with_uuid(dsd,
1237 ACPI_DSD_EXTERNAL_FACING_PORT_UUID,
1238 ACPI_DSD_EXTERNAL_FACING_PORT_NAME,
1239 1);
1240}
1241
1242/* _DSD with HotPlugSupportInD3 */
1243void acpi_device_add_hotplug_support_in_d3(struct acpi_dp *dsd)
1244{
1245 acpi_device_add_integer_property_with_uuid(dsd,
1246 ACPI_DSD_HOTPLUG_IN_D3_UUID,
1247 ACPI_DSD_HOTPLUG_IN_D3_NAME,
1248 1);
1249}
1250
1251/* _DSD with DmaProperty */
1252void acpi_device_add_dma_property(struct acpi_dp *dsd)
1253{
1254 acpi_device_add_integer_property_with_uuid(dsd,
1255 ACPI_DSD_DMA_PROPERTY_UUID,
1256 ACPI_DSD_DMA_PROPERTY_NAME,
1257 1);
1258}
1259
1260/* _DSD with StorageD3Enable */
1261void acpi_device_add_storage_d3_enable(struct acpi_dp *dsd)
1262{
1263 acpi_device_add_integer_property_with_uuid(dsd,
1264 ACPI_DSD_STORAGE_D3_UUID,
1265 ACPI_DSD_STORAGE_D3_NAME,
1266 1);
1267}