aboutsummaryrefslogtreecommitdiff
path: root/src/arch/x86/acpi_device.c
diff options
context:
space:
mode:
authorDuncan Laurie <dlaurie@chromium.org>2016-05-09 15:38:36 -0700
committerDuncan Laurie <dlaurie@google.com>2016-05-28 03:40:35 +0200
commit6b7c1f605c67f18996c584970a83fc5296c94747 (patch)
treee75e7d6cc96a97d3b4dc18b6c2da22d4ead036aa /src/arch/x86/acpi_device.c
parentb3f5418ec16b1c0cdc913d0afd49bde94c26728e (diff)
acpi_device: Add support for writing ACPI Interrupt descriptors
Add definitions for ACPI device extended interrupts and a method to write an Interrupt() descriptor to the SSDT output stream. Interrupts are often tied together with other resources and some configuration items are shared (though not always compatibly) with other constructs like GPIOs and GPEs. These will get used by device drivers to write _CRS sections for devices into the SSDT. One usage is to include a "struct acpi_irq" inside a config struct for a device so it can be initialized based on settings in devicetree. Example usage: chip.h: struct drivers_i2c_generic_config { struct acpi_irq irq; }; generic.c: void acpi_fill_ssdt_generator(struct device *dev) { struct drivers_i2c_generic_config *config = dev->chip_info; ... acpi_device_write_interrupt(&config->irq); ... } devicetree.cb: device pci 15.0 on chip drivers/i2c/generic register "irq" = "IRQ_EDGE_LOW(GPP_E7_IRQ)" device i2c 10 on end end end SSDT.dsl: Interrupt (ResourceConsumer, Edge, ActiveLow, Exclusive,,,) { 31 } Change-Id: I3b64170cc2ebac178e7a17df479eda7670a42703 Signed-off-by: Duncan Laurie <dlaurie@chromium.org> Reviewed-on: https://review.coreboot.org/14933 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'src/arch/x86/acpi_device.c')
-rw-r--r--src/arch/x86/acpi_device.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/arch/x86/acpi_device.c b/src/arch/x86/acpi_device.c
index b3861a2392..b607834349 100644
--- a/src/arch/x86/acpi_device.c
+++ b/src/arch/x86/acpi_device.c
@@ -20,6 +20,32 @@
#include <device/device.h>
#include <device/path.h>
+/* Write empty word value and return pointer to it */
+static void *acpi_device_write_zero_len(void)
+{
+ char *p = acpigen_get_current();
+ acpigen_emit_word(0);
+ return p;
+}
+
+/* Fill in length value from start to current at specified location */
+static void acpi_device_fill_from_len(char *ptr, char *start)
+{
+ uint16_t len = acpigen_get_current() - start;
+ ptr[0] = len & 0xff;
+ ptr[1] = (len >> 8) & 0xff;
+}
+
+/*
+ * Fill in the length field with the value calculated from after
+ * the 16bit field to acpigen current as this length value does
+ * not include the length field itself.
+ */
+static void acpi_device_fill_len(void *ptr)
+{
+ acpi_device_fill_from_len(ptr, ptr + sizeof(uint16_t));
+}
+
/* Locate and return the ACPI name for this device */
const char *acpi_device_name(struct device *dev)
{
@@ -109,3 +135,52 @@ const char *acpi_device_path_join(struct device *dev, const char *name)
return buf;
}
+
+/* ACPI 6.1 section 6.4.3.6: Extended Interrupt Descriptor */
+void acpi_device_write_interrupt(const struct acpi_irq *irq)
+{
+ void *desc_length;
+ uint8_t flags;
+
+ if (!irq || !irq->pin)
+ return;
+
+ /* This is supported by GpioInt() but not Interrupt() */
+ if (irq->polarity == IRQ_ACTIVE_BOTH)
+ return;
+
+ /* Byte 0: Descriptor Type */
+ acpigen_emit_byte(ACPI_DESCRIPTOR_INTERRUPT);
+
+ /* Byte 1-2: Length (filled in later) */
+ desc_length = acpi_device_write_zero_len();
+
+ /*
+ * Byte 3: Flags
+ * [7:5]: Reserved
+ * [4]: Wake (0=NO_WAKE 1=WAKE)
+ * [3]: Sharing (0=EXCLUSIVE 1=SHARED)
+ * [2]: Polarity (0=HIGH 1=LOW)
+ * [1]: Mode (0=LEVEL 1=EDGE)
+ * [0]: Resource (0=PRODUCER 1=CONSUMER)
+ */
+ flags = 1 << 0; /* ResourceConsumer */
+ if (irq->mode == IRQ_EDGE_TRIGGERED)
+ flags |= 1 << 1;
+ if (irq->polarity == IRQ_ACTIVE_LOW)
+ flags |= 1 << 2;
+ if (irq->shared == IRQ_SHARED)
+ flags |= 1 << 3;
+ if (irq->wake == IRQ_WAKE)
+ flags |= 1 << 4;
+ acpigen_emit_byte(flags);
+
+ /* Byte 4: Interrupt Table Entry Count */
+ acpigen_emit_byte(1);
+
+ /* Byte 5-8: Interrupt Number */
+ acpigen_emit_dword(irq->pin);
+
+ /* Fill in Descriptor Length (account for len word) */
+ acpi_device_fill_len(desc_length);
+}