blob: c62d6f3688ffaed92c017d7954a5a4f96b55497b [file] [log] [blame]
Duncan Lauried9af3ce2016-05-08 18:15:25 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2016 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <string.h>
17#include <arch/acpi.h>
18#include <arch/acpi_device.h>
19#include <arch/acpigen.h>
20#include <device/device.h>
21#include <device/path.h>
Duncan Lauriecfb6ea72016-05-09 17:08:38 -070022#if IS_ENABLED(CONFIG_GENERIC_GPIO_LIB)
23#include <gpio.h>
24#endif
Duncan Lauried9af3ce2016-05-08 18:15:25 -070025
Duncan Laurieffc99902016-07-02 19:56:06 -070026#define ACPI_DP_UUID "daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
27#define ACPI_DP_CHILD_UUID "dbb8e3e6-5886-4ba6-8795-1319f52a966b"
Duncan Laurie559e9472016-05-10 13:18:17 -070028
Duncan Laurie6b7c1f62016-05-09 15:38:36 -070029/* Write empty word value and return pointer to it */
30static void *acpi_device_write_zero_len(void)
31{
32 char *p = acpigen_get_current();
33 acpigen_emit_word(0);
34 return p;
35}
36
37/* Fill in length value from start to current at specified location */
38static void acpi_device_fill_from_len(char *ptr, char *start)
39{
40 uint16_t len = acpigen_get_current() - start;
41 ptr[0] = len & 0xff;
42 ptr[1] = (len >> 8) & 0xff;
43}
44
45/*
46 * Fill in the length field with the value calculated from after
47 * the 16bit field to acpigen current as this length value does
48 * not include the length field itself.
49 */
50static void acpi_device_fill_len(void *ptr)
51{
52 acpi_device_fill_from_len(ptr, ptr + sizeof(uint16_t));
53}
54
Duncan Lauried9af3ce2016-05-08 18:15:25 -070055/* Locate and return the ACPI name for this device */
56const char *acpi_device_name(struct device *dev)
57{
Duncan Laurie47029142018-05-07 14:28:53 -070058 struct device *pdev = dev;
59 const char *name = NULL;
60
Duncan Lauried9af3ce2016-05-08 18:15:25 -070061 if (!dev)
62 return NULL;
63
64 /* Check for device specific handler */
65 if (dev->ops->acpi_name)
66 return dev->ops->acpi_name(dev);
67
Duncan Laurie47029142018-05-07 14:28:53 -070068 /* Walk up the tree to find if any parent can identify this device */
69 while (pdev->bus) {
70 pdev = pdev->bus->dev;
71 if (!pdev)
72 break;
73 if (pdev->path.type == DEVICE_PATH_ROOT)
74 break;
75 if (pdev->ops && pdev->ops->acpi_name)
76 name = pdev->ops->acpi_name(dev);
77 if (name)
78 return name;
79 }
Duncan Lauried9af3ce2016-05-08 18:15:25 -070080
81 return NULL;
82}
83
84/* Recursive function to find the root device and print a path from there */
Duncan Laurie47029142018-05-07 14:28:53 -070085static ssize_t acpi_device_path_fill(struct device *dev, char *buf,
86 size_t buf_len, size_t cur)
Duncan Lauried9af3ce2016-05-08 18:15:25 -070087{
88 const char *name = acpi_device_name(dev);
Duncan Laurie47029142018-05-07 14:28:53 -070089 ssize_t next = 0;
90
91 if (!name)
92 return -1;
Duncan Lauried9af3ce2016-05-08 18:15:25 -070093
94 /*
95 * Make sure this name segment will fit, including the path segment
96 * separator and possible NUL terminator if this is the last segment.
97 */
Duncan Laurie47029142018-05-07 14:28:53 -070098 if (!dev || (cur + strlen(name) + 2) > buf_len)
Duncan Lauried9af3ce2016-05-08 18:15:25 -070099 return cur;
100
101 /* Walk up the tree to the root device */
102 if (dev->path.type != DEVICE_PATH_ROOT && dev->bus && dev->bus->dev)
103 next = acpi_device_path_fill(dev->bus->dev, buf, buf_len, cur);
Duncan Laurie47029142018-05-07 14:28:53 -0700104 if (next < 0)
105 return next;
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700106
107 /* Fill in the path from the root device */
108 next += snprintf(buf + next, buf_len - next, "%s%s",
Timothy Pearsonaeb61012017-04-13 17:06:16 -0500109 (dev->path.type == DEVICE_PATH_ROOT
110 || (strlen(name) == 0)) ?
111 "" : ".", name);
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700112
113 return next;
114}
115
116/*
117 * Warning: just as with dev_path() this uses a static buffer
118 * so should not be called mulitple times in one statement
119 */
120const char *acpi_device_path(struct device *dev)
121{
122 static char buf[DEVICE_PATH_MAX] = {};
123
124 if (!dev)
125 return NULL;
126
127 if (acpi_device_path_fill(dev, buf, sizeof(buf), 0) <= 0)
128 return NULL;
129
130 return buf;
131}
132
133/* Return the path of the parent device as the ACPI Scope for this device */
134const char *acpi_device_scope(struct device *dev)
135{
Duncan Lauried02685b2016-06-30 14:37:37 -0700136 static char buf[DEVICE_PATH_MAX] = {};
137
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700138 if (!dev || !dev->bus || !dev->bus->dev)
139 return NULL;
140
Duncan Lauried02685b2016-06-30 14:37:37 -0700141 if (acpi_device_path_fill(dev->bus->dev, buf, sizeof(buf), 0) <= 0)
142 return NULL;
143
144 return buf;
Duncan Lauried9af3ce2016-05-08 18:15:25 -0700145}
146
147/* Concatentate the device path and provided name suffix */
148const char *acpi_device_path_join(struct device *dev, const char *name)
149{
150 static char buf[DEVICE_PATH_MAX] = {};
151 size_t len;
152
153 if (!dev)
154 return NULL;
155
156 /* Build the path of this device */
157 len = acpi_device_path_fill(dev, buf, sizeof(buf), 0);
158 if (len <= 0)
159 return NULL;
160
161 /* Ensure there is room for the added name, separator, and NUL */
162 if ((len + strlen(name) + 2) > sizeof(buf))
163 return NULL;
164 snprintf(buf + len, sizeof(buf) - len, ".%s", name);
165
166 return buf;
167}
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700168
Hung-Te Linb4be50c2018-09-10 10:55:49 +0800169int acpi_device_status(const struct device *dev)
170{
171 if (!dev->enabled)
172 return ACPI_STATUS_DEVICE_ALL_OFF;
173 if (dev->hidden)
174 return ACPI_STATUS_DEVICE_HIDDEN_ON;
175 return ACPI_STATUS_DEVICE_ALL_ON;
176}
177
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700178/* ACPI 6.1 section 6.4.3.6: Extended Interrupt Descriptor */
179void acpi_device_write_interrupt(const struct acpi_irq *irq)
180{
181 void *desc_length;
182 uint8_t flags;
183
184 if (!irq || !irq->pin)
185 return;
186
187 /* This is supported by GpioInt() but not Interrupt() */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800188 if (irq->polarity == ACPI_IRQ_ACTIVE_BOTH)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700189 return;
190
191 /* Byte 0: Descriptor Type */
192 acpigen_emit_byte(ACPI_DESCRIPTOR_INTERRUPT);
193
194 /* Byte 1-2: Length (filled in later) */
195 desc_length = acpi_device_write_zero_len();
196
197 /*
198 * Byte 3: Flags
199 * [7:5]: Reserved
200 * [4]: Wake (0=NO_WAKE 1=WAKE)
201 * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
202 * [2]: Polarity (0=HIGH 1=LOW)
203 * [1]: Mode (0=LEVEL 1=EDGE)
204 * [0]: Resource (0=PRODUCER 1=CONSUMER)
205 */
206 flags = 1 << 0; /* ResourceConsumer */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800207 if (irq->mode == ACPI_IRQ_EDGE_TRIGGERED)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700208 flags |= 1 << 1;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800209 if (irq->polarity == ACPI_IRQ_ACTIVE_LOW)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700210 flags |= 1 << 2;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800211 if (irq->shared == ACPI_IRQ_SHARED)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700212 flags |= 1 << 3;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800213 if (irq->wake == ACPI_IRQ_WAKE)
Duncan Laurie6b7c1f62016-05-09 15:38:36 -0700214 flags |= 1 << 4;
215 acpigen_emit_byte(flags);
216
217 /* Byte 4: Interrupt Table Entry Count */
218 acpigen_emit_byte(1);
219
220 /* Byte 5-8: Interrupt Number */
221 acpigen_emit_dword(irq->pin);
222
223 /* Fill in Descriptor Length (account for len word) */
224 acpi_device_fill_len(desc_length);
225}
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700226
227/* ACPI 6.1 section 6.4.3.8.1 - GPIO Interrupt or I/O */
228void acpi_device_write_gpio(const struct acpi_gpio *gpio)
229{
230 void *start, *desc_length;
231 void *pin_table_offset, *vendor_data_offset, *resource_offset;
232 uint16_t flags = 0;
233 int pin;
234
235 if (!gpio || gpio->type > ACPI_GPIO_TYPE_IO)
236 return;
237
238 start = acpigen_get_current();
239
240 /* Byte 0: Descriptor Type */
241 acpigen_emit_byte(ACPI_DESCRIPTOR_GPIO);
242
243 /* Byte 1-2: Length (fill in later) */
244 desc_length = acpi_device_write_zero_len();
245
246 /* Byte 3: Revision ID */
247 acpigen_emit_byte(ACPI_GPIO_REVISION_ID);
248
249 /* Byte 4: GpioIo or GpioInt */
250 acpigen_emit_byte(gpio->type);
251
252 /*
253 * Byte 5-6: General Flags
254 * [15:1]: 0 => Reserved
255 * [0]: 1 => ResourceConsumer
256 */
257 acpigen_emit_word(1 << 0);
258
259 switch (gpio->type) {
260 case ACPI_GPIO_TYPE_INTERRUPT:
261 /*
262 * Byte 7-8: GPIO Interrupt Flags
263 * [15:5]: 0 => Reserved
264 * [4]: Wake (0=NO_WAKE 1=WAKE)
265 * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
266 * [2:1]: Polarity (0=HIGH 1=LOW 2=BOTH)
267 * [0]: Mode (0=LEVEL 1=EDGE)
268 */
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800269 if (gpio->irq.mode == ACPI_IRQ_EDGE_TRIGGERED)
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700270 flags |= 1 << 0;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800271 if (gpio->irq.shared == ACPI_IRQ_SHARED)
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700272 flags |= 1 << 3;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800273 if (gpio->irq.wake == ACPI_IRQ_WAKE)
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700274 flags |= 1 << 4;
275
276 switch (gpio->irq.polarity) {
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800277 case ACPI_IRQ_ACTIVE_HIGH:
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700278 flags |= 0 << 1;
279 break;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800280 case ACPI_IRQ_ACTIVE_LOW:
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700281 flags |= 1 << 1;
282 break;
Furquan Shaikh5b9b5932017-02-21 13:16:30 -0800283 case ACPI_IRQ_ACTIVE_BOTH:
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700284 flags |= 2 << 1;
285 break;
286 }
287 break;
288
289 case ACPI_GPIO_TYPE_IO:
290 /*
291 * Byte 7-8: GPIO IO Flags
292 * [15:4]: 0 => Reserved
293 * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
294 * [2]: 0 => Reserved
295 * [1:0]: IO Restriction
296 * 0 => IoRestrictionNone
297 * 1 => IoRestrictionInputOnly
298 * 2 => IoRestrictionOutputOnly
299 * 3 => IoRestrictionNoneAndPreserve
300 */
301 flags |= gpio->io_restrict & 3;
302 if (gpio->io_shared)
303 flags |= 1 << 3;
304 break;
305 }
306 acpigen_emit_word(flags);
307
308 /*
309 * Byte 9: Pin Configuration
310 * 0x01 => Default (no configuration applied)
311 * 0x02 => Pull-up
312 * 0x03 => Pull-down
313 * 0x04-0x7F => Reserved
314 * 0x80-0xff => Vendor defined
315 */
316 acpigen_emit_byte(gpio->pull);
317
318 /* Byte 10-11: Output Drive Strength in 1/100 mA */
319 acpigen_emit_word(gpio->output_drive_strength);
320
321 /* Byte 12-13: Debounce Timeout in 1/100 ms */
322 acpigen_emit_word(gpio->interrupt_debounce_timeout);
323
324 /* Byte 14-15: Pin Table Offset, relative to start */
325 pin_table_offset = acpi_device_write_zero_len();
326
327 /* Byte 16: Reserved */
328 acpigen_emit_byte(0);
329
330 /* Byte 17-18: Resource Source Name Offset, relative to start */
331 resource_offset = acpi_device_write_zero_len();
332
333 /* Byte 19-20: Vendor Data Offset, relative to start */
334 vendor_data_offset = acpi_device_write_zero_len();
335
336 /* Byte 21-22: Vendor Data Length */
337 acpigen_emit_word(0);
338
339 /* Fill in Pin Table Offset */
340 acpi_device_fill_from_len(pin_table_offset, start);
341
342 /* Pin Table, one word for each pin */
Duncan Laurie5b6c28c2016-06-29 10:47:22 -0700343 for (pin = 0; pin < gpio->pin_count; pin++) {
344 uint16_t acpi_pin = gpio->pins[pin];
345#if IS_ENABLED(CONFIG_GENERIC_GPIO_LIB)
346 acpi_pin = gpio_acpi_pin(acpi_pin);
347#endif
348 acpigen_emit_word(acpi_pin);
349 }
Duncan Lauriecfb6ea72016-05-09 17:08:38 -0700350
351 /* Fill in Resource Source Name Offset */
352 acpi_device_fill_from_len(resource_offset, start);
353
354 /* Resource Source Name String */
355#if IS_ENABLED(CONFIG_GENERIC_GPIO_LIB)
356 acpigen_emit_string(gpio->resource ? : gpio_acpi_path(gpio->pins[0]));
357#else
358 acpigen_emit_string(gpio->resource);
359#endif
360
361 /* Fill in Vendor Data Offset */
362 acpi_device_fill_from_len(vendor_data_offset, start);
363
364 /* Fill in GPIO Descriptor Length (account for len word) */
365 acpi_device_fill_len(desc_length);
366}
Duncan Laurie1010b4a2016-05-09 20:10:47 -0700367
368/* ACPI 6.1 section 6.4.3.8.2.1 - I2cSerialBus() */
369void acpi_device_write_i2c(const struct acpi_i2c *i2c)
370{
371 void *desc_length, *type_length;
372
373 /* Byte 0: Descriptor Type */
374 acpigen_emit_byte(ACPI_DESCRIPTOR_SERIAL_BUS);
375
376 /* Byte 1+2: Length (filled in later) */
377 desc_length = acpi_device_write_zero_len();
378
379 /* Byte 3: Revision ID */
380 acpigen_emit_byte(ACPI_SERIAL_BUS_REVISION_ID);
381
382 /* Byte 4: Resource Source Index is Reserved */
383 acpigen_emit_byte(0);
384
385 /* Byte 5: Serial Bus Type is I2C */
386 acpigen_emit_byte(ACPI_SERIAL_BUS_TYPE_I2C);
387
388 /*
389 * Byte 6: Flags
390 * [7:2]: 0 => Reserved
391 * [1]: 1 => ResourceConsumer
392 * [0]: 0 => ControllerInitiated
393 */
394 acpigen_emit_byte(1 << 1);
395
396 /*
397 * Byte 7-8: Type Specific Flags
398 * [15:1]: 0 => Reserved
399 * [0]: 0 => 7bit, 1 => 10bit
400 */
401 acpigen_emit_word(i2c->mode_10bit);
402
403 /* Byte 9: Type Specific Revision ID */
404 acpigen_emit_byte(ACPI_SERIAL_BUS_REVISION_ID);
405
406 /* Byte 10-11: I2C Type Data Length */
407 type_length = acpi_device_write_zero_len();
408
409 /* Byte 12-15: I2C Bus Speed */
410 acpigen_emit_dword(i2c->speed);
411
412 /* Byte 16-17: I2C Slave Address */
413 acpigen_emit_word(i2c->address);
414
415 /* Fill in Type Data Length */
416 acpi_device_fill_len(type_length);
417
418 /* Byte 18+: ResourceSource */
419 acpigen_emit_string(i2c->resource);
420
421 /* Fill in I2C Descriptor Length */
422 acpi_device_fill_len(desc_length);
423}
Duncan Laurie70c86d92016-05-10 07:26:34 -0700424
425/* ACPI 6.1 section 6.4.3.8.2.2 - SpiSerialBus() */
426void acpi_device_write_spi(const struct acpi_spi *spi)
427{
428 void *desc_length, *type_length;
429 uint16_t flags = 0;
430
431 /* Byte 0: Descriptor Type */
432 acpigen_emit_byte(ACPI_DESCRIPTOR_SERIAL_BUS);
433
434 /* Byte 1+2: Length (filled in later) */
435 desc_length = acpi_device_write_zero_len();
436
437 /* Byte 3: Revision ID */
438 acpigen_emit_byte(ACPI_SERIAL_BUS_REVISION_ID);
439
440 /* Byte 4: Resource Source Index is Reserved */
441 acpigen_emit_byte(0);
442
443 /* Byte 5: Serial Bus Type is SPI */
444 acpigen_emit_byte(ACPI_SERIAL_BUS_TYPE_SPI);
445
446 /*
447 * Byte 6: Flags
448 * [7:2]: 0 => Reserved
449 * [1]: 1 => ResourceConsumer
450 * [0]: 0 => ControllerInitiated
451 */
452 acpigen_emit_byte(1 << 1);
453
454 /*
455 * Byte 7-8: Type Specific Flags
456 * [15:2]: 0 => Reserved
457 * [1]: 0 => ActiveLow, 1 => ActiveHigh
458 * [0]: 0 => FourWire, 1 => ThreeWire
459 */
460 if (spi->wire_mode == SPI_3_WIRE_MODE)
461 flags |= 1 << 0;
462 if (spi->device_select_polarity == SPI_POLARITY_HIGH)
463 flags |= 1 << 1;
464 acpigen_emit_word(flags);
465
466 /* Byte 9: Type Specific Revision ID */
467 acpigen_emit_byte(ACPI_SERIAL_BUS_REVISION_ID);
468
469 /* Byte 10-11: SPI Type Data Length */
470 type_length = acpi_device_write_zero_len();
471
472 /* Byte 12-15: Connection Speed */
473 acpigen_emit_dword(spi->speed);
474
475 /* Byte 16: Data Bit Length */
476 acpigen_emit_byte(spi->data_bit_length);
477
478 /* Byte 17: Clock Phase */
479 acpigen_emit_byte(spi->clock_phase);
480
481 /* Byte 18: Clock Polarity */
482 acpigen_emit_byte(spi->clock_polarity);
483
484 /* Byte 19-20: Device Selection */
485 acpigen_emit_word(spi->device_select);
486
487 /* Fill in Type Data Length */
488 acpi_device_fill_len(type_length);
489
490 /* Byte 21+: ResourceSource String */
491 acpigen_emit_string(spi->resource);
492
493 /* Fill in SPI Descriptor Length */
494 acpi_device_fill_len(desc_length);
495}
Duncan Laurie559e9472016-05-10 13:18:17 -0700496
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800497/* PowerResource() with Enable and/or Reset control */
Shelley Chena0603392018-04-26 13:52:30 -0700498void acpi_device_add_power_res(const struct acpi_power_res_params *params)
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800499{
Lee Leahy0b5678f2017-03-16 16:01:40 -0700500 static const char *power_res_dev_states[] = { "_PR0", "_PR3" };
Shelley Chena0603392018-04-26 13:52:30 -0700501 unsigned int reset_gpio = params->reset_gpio->pins[0];
502 unsigned int enable_gpio = params->enable_gpio->pins[0];
503 unsigned int stop_gpio = params->stop_gpio->pins[0];
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800504
Furquan Shaikhedf459f2017-08-28 17:20:49 -0700505 if (!reset_gpio && !enable_gpio && !stop_gpio)
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800506 return;
507
508 /* PowerResource (PRIC, 0, 0) */
509 acpigen_write_power_res("PRIC", 0, 0, power_res_dev_states,
510 ARRAY_SIZE(power_res_dev_states));
511
512 /* Method (_STA, 0, NotSerialized) { Return (0x1) } */
513 acpigen_write_STA(0x1);
514
515 /* Method (_ON, 0, Serialized) */
516 acpigen_write_method_serialized("_ON", 0);
517 if (reset_gpio)
Shelley Chena0603392018-04-26 13:52:30 -0700518 acpigen_enable_tx_gpio(params->reset_gpio);
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800519 if (enable_gpio) {
Shelley Chena0603392018-04-26 13:52:30 -0700520 acpigen_enable_tx_gpio(params->enable_gpio);
521 if (params->enable_delay_ms)
522 acpigen_write_sleep(params->enable_delay_ms);
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800523 }
524 if (reset_gpio) {
Shelley Chena0603392018-04-26 13:52:30 -0700525 acpigen_disable_tx_gpio(params->reset_gpio);
526 if (params->reset_delay_ms)
527 acpigen_write_sleep(params->reset_delay_ms);
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800528 }
Furquan Shaikhedf459f2017-08-28 17:20:49 -0700529 if (stop_gpio) {
Shelley Chena0603392018-04-26 13:52:30 -0700530 acpigen_disable_tx_gpio(params->stop_gpio);
531 if (params->stop_delay_ms)
532 acpigen_write_sleep(params->stop_delay_ms);
Furquan Shaikhedf459f2017-08-28 17:20:49 -0700533 }
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800534 acpigen_pop_len(); /* _ON method */
535
536 /* Method (_OFF, 0, Serialized) */
537 acpigen_write_method_serialized("_OFF", 0);
Shelley Chena0603392018-04-26 13:52:30 -0700538 if (stop_gpio) {
539 acpigen_enable_tx_gpio(params->stop_gpio);
540 if (params->stop_off_delay_ms)
541 acpigen_write_sleep(params->stop_off_delay_ms);
542 }
543 if (reset_gpio) {
544 acpigen_enable_tx_gpio(params->reset_gpio);
545 if (params->reset_off_delay_ms)
546 acpigen_write_sleep(params->reset_off_delay_ms);
547 }
548 if (enable_gpio) {
549 acpigen_disable_tx_gpio(params->enable_gpio);
550 if (params->enable_off_delay_ms)
551 acpigen_write_sleep(params->enable_off_delay_ms);
552 }
Duncan Lauriebd73dbb2017-02-17 17:05:03 -0800553 acpigen_pop_len(); /* _OFF method */
554
555 acpigen_pop_len(); /* PowerResource PRIC */
556}
557
Duncan Laurieffc99902016-07-02 19:56:06 -0700558static void acpi_dp_write_array(const struct acpi_dp *array);
559static void acpi_dp_write_value(const struct acpi_dp *prop)
Duncan Laurie559e9472016-05-10 13:18:17 -0700560{
561 switch (prop->type) {
562 case ACPI_DP_TYPE_INTEGER:
563 acpigen_write_integer(prop->integer);
564 break;
565 case ACPI_DP_TYPE_STRING:
Harsha Priya3a96ac42016-07-15 17:31:43 -0700566 case ACPI_DP_TYPE_CHILD:
Duncan Laurie559e9472016-05-10 13:18:17 -0700567 acpigen_write_string(prop->string);
568 break;
569 case ACPI_DP_TYPE_REFERENCE:
570 acpigen_emit_namestring(prop->string);
571 break;
Duncan Laurieffc99902016-07-02 19:56:06 -0700572 case ACPI_DP_TYPE_ARRAY:
573 acpi_dp_write_array(prop->array);
574 break;
575 default:
576 break;
Duncan Laurie559e9472016-05-10 13:18:17 -0700577 }
578}
579
Duncan Laurieffc99902016-07-02 19:56:06 -0700580/* Package (2) { "prop->name", VALUE } */
581static void acpi_dp_write_property(const struct acpi_dp *prop)
Duncan Laurie559e9472016-05-10 13:18:17 -0700582{
583 acpigen_write_package(2);
Duncan Laurieffc99902016-07-02 19:56:06 -0700584 acpigen_write_string(prop->name);
Duncan Laurie559e9472016-05-10 13:18:17 -0700585 acpi_dp_write_value(prop);
586 acpigen_pop_len();
Duncan Laurie559e9472016-05-10 13:18:17 -0700587}
588
589/* Write array of Device Properties */
Duncan Laurieffc99902016-07-02 19:56:06 -0700590static void acpi_dp_write_array(const struct acpi_dp *array)
Duncan Laurie559e9472016-05-10 13:18:17 -0700591{
Duncan Laurieffc99902016-07-02 19:56:06 -0700592 const struct acpi_dp *dp;
593 char *pkg_count;
594
595 /* Package element count determined as it is populated */
596 pkg_count = acpigen_write_package(0);
597
Furquan Shaikh35c01bc2016-10-03 23:30:14 -0700598 /*
599 * Only acpi_dp of type DP_TYPE_TABLE is allowed to be an array.
600 * DP_TYPE_TABLE does not have a value to be written. Thus, start
601 * the loop from next type in the array.
602 */
603 for (dp = array->next; dp; dp = dp->next) {
Duncan Laurieffc99902016-07-02 19:56:06 -0700604 acpi_dp_write_value(dp);
605 (*pkg_count)++;
606 }
607
Duncan Laurie559e9472016-05-10 13:18:17 -0700608 acpigen_pop_len();
Duncan Laurie559e9472016-05-10 13:18:17 -0700609}
610
Duncan Laurieffc99902016-07-02 19:56:06 -0700611static void acpi_dp_free(struct acpi_dp *dp)
Duncan Laurie559e9472016-05-10 13:18:17 -0700612{
Duncan Laurieffc99902016-07-02 19:56:06 -0700613 while (dp) {
614 struct acpi_dp *p = dp->next;
615
616 switch (dp->type) {
617 case ACPI_DP_TYPE_CHILD:
618 acpi_dp_free(dp->child);
619 break;
620 case ACPI_DP_TYPE_ARRAY:
621 acpi_dp_free(dp->array);
622 break;
623 default:
624 break;
625 }
626
627 free(dp);
628 dp = p;
629 }
Duncan Laurie559e9472016-05-10 13:18:17 -0700630}
631
Duncan Laurieffc99902016-07-02 19:56:06 -0700632void acpi_dp_write(struct acpi_dp *table)
Duncan Laurie559e9472016-05-10 13:18:17 -0700633{
Duncan Laurieffc99902016-07-02 19:56:06 -0700634 struct acpi_dp *dp, *prop;
Matt Delco08258882019-01-30 11:16:08 -0800635 char *dp_count, *prop_count = NULL;
Duncan Laurieffc99902016-07-02 19:56:06 -0700636 int child_count = 0;
637
638 if (!table || table->type != ACPI_DP_TYPE_TABLE)
639 return;
640
641 /* Name (name) */
642 acpigen_write_name(table->name);
643
644 /* Device Property list starts with the next entry */
645 prop = table->next;
646
Matt Delco08258882019-01-30 11:16:08 -0800647 /* Package (DP), default to assuming no properties or children */
648 dp_count = acpigen_write_package(0);
Duncan Laurieffc99902016-07-02 19:56:06 -0700649
650 /* Print base properties */
651 for (dp = prop; dp; dp = dp->next) {
652 if (dp->type == ACPI_DP_TYPE_CHILD) {
653 child_count++;
654 } else {
Matt Delco08258882019-01-30 11:16:08 -0800655 /*
656 * The UUID and package is only added when
657 * we come across the first property. This
658 * is to avoid creating a zero-length package
659 * in situations where there are only children.
660 */
661 if (!prop_count) {
662 *dp_count += 2;
663 /* ToUUID (ACPI_DP_UUID) */
664 acpigen_write_uuid(ACPI_DP_UUID);
665 /*
666 * Package (PROP), element count determined as
667 * it is populated
668 */
669 prop_count = acpigen_write_package(0);
670 }
Duncan Laurieffc99902016-07-02 19:56:06 -0700671 (*prop_count)++;
672 acpi_dp_write_property(dp);
673 }
674 }
Matt Delco08258882019-01-30 11:16:08 -0800675 if (prop_count) {
676 /* Package (PROP) length, if a package was written */
677 acpigen_pop_len();
678 }
Duncan Laurieffc99902016-07-02 19:56:06 -0700679
680 if (child_count) {
Matt Delco08258882019-01-30 11:16:08 -0800681 /* Update DP package count to 2 or 4 */
682 *dp_count += 2;
Duncan Laurieffc99902016-07-02 19:56:06 -0700683 /* ToUUID (ACPI_DP_CHILD_UUID) */
684 acpigen_write_uuid(ACPI_DP_CHILD_UUID);
685
686 /* Print child pointer properties */
687 acpigen_write_package(child_count);
688
689 for (dp = prop; dp; dp = dp->next)
690 if (dp->type == ACPI_DP_TYPE_CHILD)
691 acpi_dp_write_property(dp);
Matt Delco08258882019-01-30 11:16:08 -0800692 /* Package (CHILD) length */
Duncan Laurieffc99902016-07-02 19:56:06 -0700693 acpigen_pop_len();
694 }
695
696 /* Package (DP) length */
697 acpigen_pop_len();
698
699 /* Recursively parse children into separate tables */
700 for (dp = prop; dp; dp = dp->next)
701 if (dp->type == ACPI_DP_TYPE_CHILD)
702 acpi_dp_write(dp->child);
703
704 /* Clean up */
705 acpi_dp_free(table);
706}
707
708static struct acpi_dp *acpi_dp_new(struct acpi_dp *dp, enum acpi_dp_type type,
709 const char *name)
710{
711 struct acpi_dp *new;
712
713 new = malloc(sizeof(struct acpi_dp));
714 if (!new)
715 return NULL;
716
717 memset(new, 0, sizeof(*new));
718 new->type = type;
719 new->name = name;
720
721 if (dp) {
722 /* Add to end of property list */
723 while (dp->next)
724 dp = dp->next;
725 dp->next = new;
726 }
727
728 return new;
729}
730
731struct acpi_dp *acpi_dp_new_table(const char *name)
732{
733 return acpi_dp_new(NULL, ACPI_DP_TYPE_TABLE, name);
734}
735
Duncan Laurieb3023b62017-08-29 08:26:50 -0700736size_t acpi_dp_add_property_list(struct acpi_dp *dp,
737 const struct acpi_dp *property_list,
738 size_t property_count)
739{
740 const struct acpi_dp *prop;
741 size_t i, properties_added = 0;
742
743 for (i = 0; i < property_count; i++) {
744 prop = &property_list[i];
745
746 if (prop->type == ACPI_DP_TYPE_UNKNOWN || !prop->name)
747 continue;
748
749 switch (prop->type) {
750 case ACPI_DP_TYPE_INTEGER:
751 acpi_dp_add_integer(dp, prop->name, prop->integer);
752 break;
753 case ACPI_DP_TYPE_STRING:
754 acpi_dp_add_string(dp, prop->name, prop->string);
755 break;
756 case ACPI_DP_TYPE_REFERENCE:
757 acpi_dp_add_reference(dp, prop->name, prop->string);
758 break;
759 case ACPI_DP_TYPE_ARRAY:
760 acpi_dp_add_array(dp, prop->array);
761 break;
762 case ACPI_DP_TYPE_CHILD:
763 acpi_dp_add_child(dp, prop->name, prop->child);
764 break;
765 default:
766 continue;
767 }
768
769 ++properties_added;
770 }
771
772 return properties_added;
773}
774
Duncan Laurieffc99902016-07-02 19:56:06 -0700775struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
776 uint64_t value)
777{
778 struct acpi_dp *new = acpi_dp_new(dp, ACPI_DP_TYPE_INTEGER, name);
779
780 if (new)
781 new->integer = value;
782
783 return new;
784}
785
786struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
787 const char *string)
788{
789 struct acpi_dp *new = acpi_dp_new(dp, ACPI_DP_TYPE_STRING, name);
790
791 if (new)
792 new->string = string;
793
794 return new;
795}
796
797struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
798 const char *reference)
799{
800 struct acpi_dp *new = acpi_dp_new(dp, ACPI_DP_TYPE_REFERENCE, name);
801
802 if (new)
803 new->string = reference;
804
805 return new;
806}
807
808struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
809 struct acpi_dp *child)
810{
811 struct acpi_dp *new;
812
813 if (!child || child->type != ACPI_DP_TYPE_TABLE)
814 return NULL;
815
816 new = acpi_dp_new(dp, ACPI_DP_TYPE_CHILD, name);
817 if (new) {
818 new->child = child;
819 new->string = child->name;
820 }
821
822 return new;
823}
824
825struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array)
826{
827 struct acpi_dp *new;
828
829 if (!array || array->type != ACPI_DP_TYPE_TABLE)
830 return NULL;
831
832 new = acpi_dp_new(dp, ACPI_DP_TYPE_ARRAY, array->name);
833 if (new)
834 new->array = array;
835
836 return new;
837}
838
839struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
840 uint64_t *array, int len)
841{
842 struct acpi_dp *dp_array;
843 int i;
844
845 if (len <= 0)
846 return NULL;
847
848 dp_array = acpi_dp_new_table(name);
849 if (!dp_array)
850 return NULL;
851
852 for (i = 0; i < len; i++)
853 if (!acpi_dp_add_integer(dp_array, NULL, array[i]))
854 break;
855
856 acpi_dp_add_array(dp, dp_array);
857
858 return dp_array;
859}
860
861struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
862 const char *ref, int index, int pin,
863 int active_low)
864{
865 struct acpi_dp *gpio = acpi_dp_new_table(name);
866
867 if (!gpio)
868 return NULL;
869
870 /* The device that has _CRS containing GpioIO()/GpioInt() */
871 acpi_dp_add_reference(gpio, NULL, ref);
872
873 /* Index of the GPIO resource in _CRS starting from zero */
874 acpi_dp_add_integer(gpio, NULL, index);
875
876 /* Pin in the GPIO resource, typically zero */
877 acpi_dp_add_integer(gpio, NULL, pin);
878
879 /* Set if pin is active low */
880 acpi_dp_add_integer(gpio, NULL, active_low);
881
882 acpi_dp_add_array(dp, gpio);
883
884 return gpio;
Duncan Laurie559e9472016-05-10 13:18:17 -0700885}