summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/acpi_device.c354
-rw-r--r--src/arch/x86/include/arch/acpi_device.h114
-rw-r--r--src/drivers/generic/max98357a/max98357a.c9
-rw-r--r--src/drivers/i2c/nau8825/nau8825.c14
-rw-r--r--src/soc/intel/skylake/sd.c7
5 files changed, 345 insertions, 153 deletions
diff --git a/src/arch/x86/acpi_device.c b/src/arch/x86/acpi_device.c
index f8f6a6dbe9..ce31dc8e21 100644
--- a/src/arch/x86/acpi_device.c
+++ b/src/arch/x86/acpi_device.c
@@ -24,14 +24,31 @@
#include <gpio.h>
#endif
-/*
- * Pointer to length field in device properties package
- * Location is set in dp_header() and length filled in by dp_footer()
- */
-static char *dp_count_ptr;
-
-/* Count of the number of device properties in the current set */
-static char dp_count;
+#define ACPI_DP_UUID "daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
+#define ACPI_DP_CHILD_UUID "dbb8e3e6-5886-4ba6-8795-1319f52a966b"
+
+enum acpi_dp_type {
+ ACPI_DP_TYPE_INTEGER,
+ ACPI_DP_TYPE_STRING,
+ ACPI_DP_TYPE_REFERENCE,
+ ACPI_DP_TYPE_TABLE,
+ ACPI_DP_TYPE_ARRAY,
+ ACPI_DP_TYPE_CHILD,
+};
+
+struct acpi_dp {
+ enum acpi_dp_type type;
+ const char *name;
+ struct acpi_dp *next;
+ union {
+ struct acpi_dp *child;
+ struct acpi_dp *array;
+ };
+ union {
+ uint64_t integer;
+ const char *string;
+ };
+};
/* Write empty word value and return pointer to it */
static void *acpi_device_write_zero_len(void)
@@ -473,39 +490,8 @@ void acpi_device_write_spi(const struct acpi_spi *spi)
acpi_device_fill_len(desc_length);
}
-/* Write a header for using _DSD to export Device Properties */
-void acpi_dp_write_header(void)
-{
- /* Name (_DSD) */
- acpigen_write_name("_DSD");
-
- /* Package (2) */
- acpigen_write_package(2);
-
- /* ToUUID (ACPI_DP_UUID) */
- acpigen_write_uuid(ACPI_DP_UUID);
-
- /* Package (X) */
- acpigen_emit_byte(0x12);
- acpigen_write_len_f();
- dp_count_ptr = acpigen_get_current();
- acpigen_emit_byte(0); /* Number of elements, filled by dp_footer */
-
- /* Reset element counter */
- dp_count = 0;
-}
-
-/* Fill in length values from writing Device Properties */
-void acpi_dp_write_footer(void)
-{
- /* Patch device property element count */
- *dp_count_ptr = dp_count;
-
- acpigen_pop_len(); /* Inner package length */
- acpigen_pop_len(); /* Outer package length */
-}
-
-void acpi_dp_write_value(const struct acpi_dp *prop)
+static void acpi_dp_write_array(const struct acpi_dp *array);
+static void acpi_dp_write_value(const struct acpi_dp *prop)
{
switch (prop->type) {
case ACPI_DP_TYPE_INTEGER:
@@ -515,86 +501,266 @@ void acpi_dp_write_value(const struct acpi_dp *prop)
acpigen_write_string(prop->string);
break;
case ACPI_DP_TYPE_REFERENCE:
+ case ACPI_DP_TYPE_CHILD:
acpigen_emit_namestring(prop->string);
break;
+ case ACPI_DP_TYPE_ARRAY:
+ acpi_dp_write_array(prop->array);
+ break;
+ default:
+ break;
}
}
-/* Write Device Property key with value as an integer */
-void acpi_dp_write_keyval(const char *key, const struct acpi_dp *prop)
+/* Package (2) { "prop->name", VALUE } */
+static void acpi_dp_write_property(const struct acpi_dp *prop)
{
acpigen_write_package(2);
- acpigen_write_string(key);
+ acpigen_write_string(prop->name);
acpi_dp_write_value(prop);
acpigen_pop_len();
- dp_count++;
}
-/* Write Device Property key with value as an integer */
-void acpi_dp_write_integer(const char *key, uint64_t value)
+/* Write array of Device Properties */
+static void acpi_dp_write_array(const struct acpi_dp *array)
{
- const struct acpi_dp prop = ACPI_DP_INTEGER(value);
- acpi_dp_write_keyval(key, &prop);
-}
+ const struct acpi_dp *dp;
+ char *pkg_count;
-/* Write Device Property key with value as a string */
-void acpi_dp_write_string(const char *key, const char *value)
-{
- const struct acpi_dp prop = ACPI_DP_STRING(value);
- acpi_dp_write_keyval(key, &prop);
+ /* Package element count determined as it is populated */
+ pkg_count = acpigen_write_package(0);
+
+ for (dp = array; dp; dp = dp->next) {
+ acpi_dp_write_value(dp);
+ (*pkg_count)++;
+ }
+
+ acpigen_pop_len();
}
-/* Write Device Property key with value as a reference */
-void acpi_dp_write_reference(const char *key, const char *value)
+static void acpi_dp_free(struct acpi_dp *dp)
{
- const struct acpi_dp prop = ACPI_DP_REFERENCE(value);
- acpi_dp_write_keyval(key, &prop);
+ while (dp) {
+ struct acpi_dp *p = dp->next;
+
+ switch (dp->type) {
+ case ACPI_DP_TYPE_CHILD:
+ acpi_dp_free(dp->child);
+ break;
+ case ACPI_DP_TYPE_ARRAY:
+ acpi_dp_free(dp->array);
+ break;
+ default:
+ break;
+ }
+
+ free(dp);
+ dp = p;
+ }
}
-/* Write array of Device Properties */
-void acpi_dp_write_array(const char *key, const struct acpi_dp *array, int len)
+void acpi_dp_write(struct acpi_dp *table)
{
- int i;
- acpigen_write_package(2);
- acpigen_write_string(key);
- acpigen_write_package(len);
- for (i = 0; i < len; i++)
- acpi_dp_write_value(&array[i]);
+ struct acpi_dp *dp, *prop;
+ char *dp_count, *prop_count;
+ int child_count = 0;
+
+ if (!table || table->type != ACPI_DP_TYPE_TABLE)
+ return;
+
+ /* Name (name) */
+ acpigen_write_name(table->name);
+
+ /* Device Property list starts with the next entry */
+ prop = table->next;
+
+ /* Package (DP), default to 2 elements (assuming no children) */
+ dp_count = acpigen_write_package(2);
+
+ /* ToUUID (ACPI_DP_UUID) */
+ acpigen_write_uuid(ACPI_DP_UUID);
+
+ /* Package (PROP), element count determined as it is populated */
+ prop_count = acpigen_write_package(0);
+
+ /* Print base properties */
+ for (dp = prop; dp; dp = dp->next) {
+ if (dp->type == ACPI_DP_TYPE_CHILD) {
+ child_count++;
+ } else {
+ (*prop_count)++;
+ acpi_dp_write_property(dp);
+ }
+ }
+
+ /* Package (PROP) length */
acpigen_pop_len();
+
+ if (child_count) {
+ /* Update DP package count to 4 */
+ *dp_count = 4;
+
+ /* ToUUID (ACPI_DP_CHILD_UUID) */
+ acpigen_write_uuid(ACPI_DP_CHILD_UUID);
+
+ /* Print child pointer properties */
+ acpigen_write_package(child_count);
+
+ for (dp = prop; dp; dp = dp->next)
+ if (dp->type == ACPI_DP_TYPE_CHILD)
+ acpi_dp_write_property(dp);
+
+ acpigen_pop_len();
+ }
+
+ /* Package (DP) length */
acpigen_pop_len();
- dp_count++;
+
+ /* Recursively parse children into separate tables */
+ for (dp = prop; dp; dp = dp->next)
+ if (dp->type == ACPI_DP_TYPE_CHILD)
+ acpi_dp_write(dp->child);
+
+ /* Clean up */
+ acpi_dp_free(table);
+}
+
+static struct acpi_dp *acpi_dp_new(struct acpi_dp *dp, enum acpi_dp_type type,
+ const char *name)
+{
+ struct acpi_dp *new;
+
+ new = malloc(sizeof(struct acpi_dp));
+ if (!new)
+ return NULL;
+
+ memset(new, 0, sizeof(*new));
+ new->type = type;
+ new->name = name;
+
+ if (dp) {
+ /* Add to end of property list */
+ while (dp->next)
+ dp = dp->next;
+ dp->next = new;
+ }
+
+ return new;
+}
+
+struct acpi_dp *acpi_dp_new_table(const char *name)
+{
+ return acpi_dp_new(NULL, ACPI_DP_TYPE_TABLE, name);
+}
+
+struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
+ uint64_t value)
+{
+ struct acpi_dp *new = acpi_dp_new(dp, ACPI_DP_TYPE_INTEGER, name);
+
+ if (new)
+ new->integer = value;
+
+ return new;
+}
+
+struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
+ const char *string)
+{
+ struct acpi_dp *new = acpi_dp_new(dp, ACPI_DP_TYPE_STRING, name);
+
+ if (new)
+ new->string = string;
+
+ return new;
+}
+
+struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
+ const char *reference)
+{
+ struct acpi_dp *new = acpi_dp_new(dp, ACPI_DP_TYPE_REFERENCE, name);
+
+ if (new)
+ new->string = reference;
+
+ return new;
}
-/* Write array of Device Properties with values as integers */
-void acpi_dp_write_integer_array(const char *key, uint64_t *array, int len)
+struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
+ struct acpi_dp *child)
{
+ struct acpi_dp *new;
+
+ if (!child || child->type != ACPI_DP_TYPE_TABLE)
+ return NULL;
+
+ new = acpi_dp_new(dp, ACPI_DP_TYPE_CHILD, name);
+ if (new) {
+ new->child = child;
+ new->string = child->name;
+ }
+
+ return new;
+}
+
+struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array)
+{
+ struct acpi_dp *new;
+
+ if (!array || array->type != ACPI_DP_TYPE_TABLE)
+ return NULL;
+
+ new = acpi_dp_new(dp, ACPI_DP_TYPE_ARRAY, array->name);
+ if (new)
+ new->array = array;
+
+ return new;
+}
+
+struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
+ uint64_t *array, int len)
+{
+ struct acpi_dp *dp_array;
int i;
- acpigen_write_package(2);
- acpigen_write_string(key);
- acpigen_write_package(len);
+
+ if (len <= 0)
+ return NULL;
+
+ dp_array = acpi_dp_new_table(name);
+ if (!dp_array)
+ return NULL;
+
for (i = 0; i < len; i++)
- acpigen_write_integer(array[i]);
- acpigen_pop_len();
- acpigen_pop_len();
- dp_count++;
+ if (!acpi_dp_add_integer(dp_array, NULL, array[i]))
+ break;
+
+ acpi_dp_add_array(dp, dp_array);
+
+ return dp_array;
}
-/*
- * Device Properties for GPIO binding
- * linux/Documentation/acpi/gpio-properties.txt
- */
-void acpi_dp_write_gpio(const char *key, const char *ref, int index,
- int pin, int active_low)
+struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
+ const char *ref, int index, int pin,
+ int active_low)
{
- const struct acpi_dp gpio_prop[] = {
- /* The device that has _CRS containing GpioIo()/GpioInt() */
- ACPI_DP_REFERENCE(ref),
- /* Index of the GPIO resource in _CRS starting from zero */
- ACPI_DP_INTEGER(index),
- /* Pin in the GPIO resource, typically zero */
- ACPI_DP_INTEGER(pin),
- /* Set if pin is active low */
- ACPI_DP_INTEGER(active_low)
- };
- acpi_dp_write_array(key, gpio_prop, ARRAY_SIZE(gpio_prop));
+ struct acpi_dp *gpio = acpi_dp_new_table(name);
+
+ if (!gpio)
+ return NULL;
+
+ /* The device that has _CRS containing GpioIO()/GpioInt() */
+ acpi_dp_add_reference(gpio, NULL, ref);
+
+ /* Index of the GPIO resource in _CRS starting from zero */
+ acpi_dp_add_integer(gpio, NULL, index);
+
+ /* Pin in the GPIO resource, typically zero */
+ acpi_dp_add_integer(gpio, NULL, pin);
+
+ /* Set if pin is active low */
+ acpi_dp_add_integer(gpio, NULL, active_low);
+
+ acpi_dp_add_array(dp, gpio);
+
+ return gpio;
}
diff --git a/src/arch/x86/include/arch/acpi_device.h b/src/arch/x86/include/arch/acpi_device.h
index 65f49b2cb0..4b3a469199 100644
--- a/src/arch/x86/include/arch/acpi_device.h
+++ b/src/arch/x86/include/arch/acpi_device.h
@@ -229,63 +229,85 @@ struct acpi_spi {
void acpi_device_write_spi(const struct acpi_spi *spi);
/*
- * Device Properties with _DSD
- * http://uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
- */
-
-#define ACPI_DP_UUID "daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
-
-enum acpi_dp_type {
- ACPI_DP_TYPE_INTEGER,
- ACPI_DP_TYPE_STRING,
- ACPI_DP_TYPE_REFERENCE,
-};
-
-struct acpi_dp {
- enum acpi_dp_type type;
- union {
- uint64_t integer;
- const char *string;
- };
-};
-
-#define ACPI_DP_INTEGER(x) { .type = ACPI_DP_TYPE_INTEGER, .integer = x }
-#define ACPI_DP_STRING(x) { .type = ACPI_DP_TYPE_STRING, .string = x }
-#define ACPI_DP_REFERENCE(x) { .type = ACPI_DP_TYPE_REFERENCE, .string = x }
-
-/*
* Writing Device Properties objects via _DSD
+ *
+ * http://uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
+ * http://uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.pdf
+ *
+ * The Device Property Hierarchy can be multiple levels deep with multiple
+ * children possible in each level. In order to support this flexibility
+ * the device property hierarchy must be built up before being written out.
+ *
+ * For example:
+ *
+ * // Child table with string and integer
+ * struct acpi_dp *child = acpi_dp_new_table("CHLD");
+ * acpi_dp_add_string(child, "childstring", "CHILD");
+ * acpi_dp_add_integer(child, "childint", 100);
+ *
+ * // _DSD table with integer and gpio and child pointer
+ * struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
+ * acpi_dp_add_integer(dsd, "number1", 1);
+ * acpi_dp_add_gpio(dsd, "gpio", "\_SB.PCI0.GPIO", 0, 0, 1);
+ * acpi_dp_add_child(dsd, "child", child);
+ *
+ * // Write entries into SSDT and clean up resources
+ * acpi_dp_write(dsd);
+ *
+ * Name(_DSD, Package() {
+ * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
+ * Package() {
+ * Package() { "gpio", Package() { \_SB.PCI0.GPIO, 0, 0, 0 } }
+ * Package() { "number1", 1 }
+ * }
+ * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b")
+ * Package() {
+ * Package() { "child", CHLD }
+ * }
+ * }
+ * Name(CHLD, Package() {
+ * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
+ * Package() {
+ * Package() { "childstring", "CHILD" }
+ * Package() { "childint", 100 }
+ * }
+ * }
*/
-/* Start a set of Device Properties with _DSD and UUID */
-void acpi_dp_write_header(void);
+struct acpi_dp;
-/* End the Device Properties set and fill in length values */
-void acpi_dp_write_footer(void);
+/* Start a new Device Property table with provided ACPI reference */
+struct acpi_dp *acpi_dp_new_table(const char *ref);
-/* Write a Device Property value, but not the key */
-void acpi_dp_write_value(const struct acpi_dp *prop);
+/* Add integer Device Property */
+struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
+ uint64_t value);
-/* Write a Device Property, both key and value */
-void acpi_dp_write_keyval(const char *key, const struct acpi_dp *prop);
+/* Add string Device Property */
+struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
+ const char *string);
-/* Write an integer as a Device Property */
-void acpi_dp_write_integer(const char *key, uint64_t value);
+/* Add ACPI reference Device Property */
+struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
+ const char *reference);
-/* Write a string as a Device Property */
-void acpi_dp_write_string(const char *key, const char *value);
+/* Add an array of Device Properties */
+struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array);
-/* Write an ACPI reference as a Device Property */
-void acpi_dp_write_reference(const char *key, const char *value);
+/* Add an array of integers Device Property */
+struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
+ uint64_t *array, int len);
-/* Write an array of Device Properties */
-void acpi_dp_write_array(const char *key, const struct acpi_dp *array, int len);
+/* Add a GPIO binding Device Property */
+struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
+ const char *ref, int index, int pin,
+ int active_low);
-/* Write an array of integers as Device Properties */
-void acpi_dp_write_integer_array(const char *key, uint64_t *array, int len);
+/* Add a child table of Device Properties */
+struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
+ struct acpi_dp *child);
-/* Write a GPIO binding Device Property */
-void acpi_dp_write_gpio(const char *key, const char *ref, int index,
- int pin, int active_low);
+/* Write Device Property hierarchy and clean up resources */
+void acpi_dp_write(struct acpi_dp *table);
#endif
diff --git a/src/drivers/generic/max98357a/max98357a.c b/src/drivers/generic/max98357a/max98357a.c
index 0d522d45c0..25e5104129 100644
--- a/src/drivers/generic/max98357a/max98357a.c
+++ b/src/drivers/generic/max98357a/max98357a.c
@@ -32,6 +32,7 @@ static void max98357a_fill_ssdt(struct device *dev)
{
struct drivers_generic_max98357a_config *config = dev->chip_info;
const char *path;
+ struct acpi_dp *dp;
if (!dev->enabled || !config)
return;
@@ -51,12 +52,12 @@ static void max98357a_fill_ssdt(struct device *dev)
acpigen_write_resourcetemplate_footer();
/* _DSD for devicetree properties */
- acpi_dp_write_header();
/* This points to the first pin in the first gpio entry in _CRS */
path = acpi_device_path(dev);
- acpi_dp_write_gpio("sdmode-gpio", path, 0, 0, 0);
- acpi_dp_write_integer("sdmode-delay", config->sdmode_delay);
- acpi_dp_write_footer();
+ dp = acpi_dp_new_table("_DSD");
+ acpi_dp_add_gpio(dp, "sdmode-gpio", path, 0, 0, 0);
+ acpi_dp_add_integer(dp, "sdmode-delay", config->sdmode_delay);
+ acpi_dp_write(dp);
acpigen_pop_len(); /* Device */
acpigen_pop_len(); /* Scope */
diff --git a/src/drivers/i2c/nau8825/nau8825.c b/src/drivers/i2c/nau8825/nau8825.c
index 71aaceaf15..a86eff41f3 100644
--- a/src/drivers/i2c/nau8825/nau8825.c
+++ b/src/drivers/i2c/nau8825/nau8825.c
@@ -28,7 +28,9 @@
#define NAU8825_ACPI_NAME "NAU8"
#define NAU8825_ACPI_HID "10508825"
-#define NAU8825_DP_INT(key,val) acpi_dp_write_integer("nuvoton," key, (val))
+
+#define NAU8825_DP_INT(key,val) \
+ acpi_dp_add_integer(dp, "nuvoton," key, (val))
static void nau8825_fill_ssdt(struct device *dev)
{
@@ -40,6 +42,7 @@ static void nau8825_fill_ssdt(struct device *dev)
.speed = config->bus_speed ? : I2C_SPEED_FAST,
.resource = scope,
};
+ struct acpi_dp *dp = NULL;
if (!dev->enabled || !scope)
return;
@@ -62,7 +65,7 @@ static void nau8825_fill_ssdt(struct device *dev)
acpigen_write_resourcetemplate_footer();
/* Device Properties */
- acpi_dp_write_header();
+ dp = acpi_dp_new_table("_DSD");
NAU8825_DP_INT("jkdet-enable", config->jkdet_enable);
NAU8825_DP_INT("jkdet-pull-enable", config->jkdet_pull_enable);
NAU8825_DP_INT("jkdet-pull-up", config->jkdet_pull_up);
@@ -77,10 +80,9 @@ static void nau8825_fill_ssdt(struct device *dev)
NAU8825_DP_INT("jack-insert-debounce", config->jack_insert_debounce);
NAU8825_DP_INT("jack-eject-deboune", config->jack_eject_debounce);
NAU8825_DP_INT("sar-threshold-num", config->sar_threshold_num);
- acpi_dp_write_integer_array("nuvoton,sar-threshold",
- config->sar_threshold,
- config->sar_threshold_num);
- acpi_dp_write_footer();
+ acpi_dp_add_integer_array(dp, "nuvoton,sar-threshold",
+ config->sar_threshold, config->sar_threshold_num);
+ acpi_dp_write(dp);
acpigen_pop_len(); /* Device */
acpigen_pop_len(); /* Scope */
diff --git a/src/soc/intel/skylake/sd.c b/src/soc/intel/skylake/sd.c
index 80adb9c467..a75cf635d3 100644
--- a/src/soc/intel/skylake/sd.c
+++ b/src/soc/intel/skylake/sd.c
@@ -38,6 +38,7 @@ static void sd_fill_ssdt(struct device *dev)
.pin_count = 1,
.pins = { config->sdcard_cd_gpio_default }
};
+ struct acpi_dp *dp;
if (!dev->enabled)
return;
@@ -62,9 +63,9 @@ static void sd_fill_ssdt(struct device *dev)
acpigen_write_resourcetemplate_footer();
/* Bind the cd-gpio name to the GpioInt() resource */
- acpi_dp_write_header();
- acpi_dp_write_gpio("cd-gpio", path, 0, 0, 1);
- acpi_dp_write_footer();
+ dp = acpi_dp_new_table("_DSD");
+ acpi_dp_add_gpio(dp, "cd-gpio", path, 0, 0, 1);
+ acpi_dp_write(dp);
acpigen_pop_len();
}