coreboot-kgpe-d16/src/include/acpi/acpi_device.h

592 lines
18 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __ACPI_ACPI_DEVICE_H__
#define __ACPI_ACPI_DEVICE_H__
#include <device/i2c.h>
#include <spi-generic.h>
#include <types.h>
enum acpi_dp_type {
ACPI_DP_TYPE_UNKNOWN,
ACPI_DP_TYPE_INTEGER,
ACPI_DP_TYPE_STRING,
ACPI_DP_TYPE_REFERENCE,
ACPI_DP_TYPE_TABLE,
ACPI_DP_TYPE_ARRAY,
ACPI_DP_TYPE_CHILD,
ACPI_DP_TYPE_PACKAGE,
};
struct acpi_dp {
enum acpi_dp_type type;
const char *name;
const char *uuid;
struct acpi_dp *next;
union {
struct acpi_dp *child;
struct acpi_dp *array;
};
union {
uint64_t integer;
const char *string;
};
};
#define ACPI_DESCRIPTOR_LARGE (1 << 7)
#define ACPI_DESCRIPTOR_INTERRUPT (ACPI_DESCRIPTOR_LARGE | 9)
#define ACPI_DESCRIPTOR_GPIO (ACPI_DESCRIPTOR_LARGE | 12)
#define ACPI_DESCRIPTOR_SERIAL_BUS (ACPI_DESCRIPTOR_LARGE | 14)
/*
* PRP0001 is a special DT namespace link device ID. It provides a means to use
* existing DT-compatible device identification in ACPI. When this _HID is used
* by an ACPI device, the ACPI subsystem in OS looks up "compatible" property in
* device object's _DSD and will use the value of that property to identify the
* corresponding device in analogy with the original DT device identification
* algorithm.
* More details can be found in Linux kernel documentation:
* Documentation/acpi/enumeration.txt
*/
#define ACPI_DT_NAMESPACE_HID "PRP0001"
struct device;
const char *acpi_device_name(const struct device *dev);
const char *acpi_device_hid(const struct device *dev);
uint32_t acpi_device_uid(const struct device *dev);
const char *acpi_device_path(const struct device *dev);
const char *acpi_device_scope(const struct device *dev);
const char *acpi_device_path_join(const struct device *dev, const char *name);
int acpi_device_status(const struct device *dev);
void acpi_device_write_uid(const struct device *dev);
/*
* ACPI Descriptor for extended Interrupt()
*/
enum acpi_irq_mode {
ACPI_IRQ_EDGE_TRIGGERED,
ACPI_IRQ_LEVEL_TRIGGERED
};
enum acpi_irq_polarity {
ACPI_IRQ_ACTIVE_LOW,
ACPI_IRQ_ACTIVE_HIGH,
ACPI_IRQ_ACTIVE_BOTH
};
enum acpi_irq_shared {
ACPI_IRQ_EXCLUSIVE,
ACPI_IRQ_SHARED
};
enum acpi_irq_wake {
ACPI_IRQ_NO_WAKE,
ACPI_IRQ_WAKE
};
struct acpi_irq {
unsigned int pin;
enum acpi_irq_mode mode;
enum acpi_irq_polarity polarity;
enum acpi_irq_shared shared;
enum acpi_irq_wake wake;
};
#define ACPI_IRQ_CFG(_pin, _mode, _pol, _shared, _wake) { \
.pin = (_pin), \
.mode = (_mode), \
.polarity = (_pol), \
.shared = (_shared), \
.wake = (_wake) }
#define ACPI_IRQ_EDGE_LOW(x) \
ACPI_IRQ_CFG((x), ACPI_IRQ_EDGE_TRIGGERED, ACPI_IRQ_ACTIVE_LOW, \
ACPI_IRQ_EXCLUSIVE, ACPI_IRQ_NO_WAKE)
#define ACPI_IRQ_EDGE_HIGH(x) \
ACPI_IRQ_CFG((x), ACPI_IRQ_EDGE_TRIGGERED, ACPI_IRQ_ACTIVE_HIGH, \
ACPI_IRQ_EXCLUSIVE, ACPI_IRQ_NO_WAKE)
#define ACPI_IRQ_LEVEL_LOW(x) \
ACPI_IRQ_CFG((x), ACPI_IRQ_LEVEL_TRIGGERED, ACPI_IRQ_ACTIVE_LOW, \
ACPI_IRQ_SHARED, ACPI_IRQ_NO_WAKE)
#define ACPI_IRQ_LEVEL_HIGH(x) \
ACPI_IRQ_CFG((x), ACPI_IRQ_LEVEL_TRIGGERED, ACPI_IRQ_ACTIVE_HIGH, \
ACPI_IRQ_SHARED, ACPI_IRQ_NO_WAKE)
#define ACPI_IRQ_WAKE_EDGE_LOW(x) \
ACPI_IRQ_CFG((x), ACPI_IRQ_EDGE_TRIGGERED, ACPI_IRQ_ACTIVE_LOW, \
ACPI_IRQ_EXCLUSIVE, ACPI_IRQ_WAKE)
#define ACPI_IRQ_WAKE_EDGE_HIGH(x) \
ACPI_IRQ_CFG((x), ACPI_IRQ_EDGE_TRIGGERED, ACPI_IRQ_ACTIVE_HIGH, \
ACPI_IRQ_EXCLUSIVE, ACPI_IRQ_WAKE)
#define ACPI_IRQ_WAKE_LEVEL_LOW(x) \
ACPI_IRQ_CFG((x), ACPI_IRQ_LEVEL_TRIGGERED, ACPI_IRQ_ACTIVE_LOW, \
ACPI_IRQ_SHARED, ACPI_IRQ_WAKE)
#define ACPI_IRQ_WAKE_LEVEL_HIGH(x) \
ACPI_IRQ_CFG((x), ACPI_IRQ_LEVEL_TRIGGERED, ACPI_IRQ_ACTIVE_HIGH, \
ACPI_IRQ_SHARED, ACPI_IRQ_WAKE)
/* Write extended Interrupt() descriptor to SSDT AML output */
void acpi_device_write_interrupt(const struct acpi_irq *irq);
/*
* ACPI Descriptors for GpioIo() and GpioInterrupt()
*/
enum acpi_gpio_type {
ACPI_GPIO_TYPE_INTERRUPT,
ACPI_GPIO_TYPE_IO
};
enum acpi_gpio_pull {
ACPI_GPIO_PULL_DEFAULT,
ACPI_GPIO_PULL_UP,
ACPI_GPIO_PULL_DOWN,
ACPI_GPIO_PULL_NONE
};
enum acpi_gpio_io_restrict {
ACPI_GPIO_IO_RESTRICT_NONE,
ACPI_GPIO_IO_RESTRICT_INPUT,
ACPI_GPIO_IO_RESTRICT_OUTPUT,
ACPI_GPIO_IO_RESTRICT_PRESERVE
};
#define ACPI_GPIO_REVISION_ID 1
#define ACPI_GPIO_MAX_PINS 8
struct acpi_gpio {
int pin_count;
uint16_t pins[ACPI_GPIO_MAX_PINS];
enum acpi_gpio_type type;
enum acpi_gpio_pull pull;
const char *resource;
/* GpioInt */
uint16_t interrupt_debounce_timeout; /* 1/100 ms */
struct acpi_irq irq;
/* GpioIo */
uint16_t output_drive_strength; /* 1/100 mA */
int io_shared;
enum acpi_gpio_io_restrict io_restrict;
/*
* As per ACPI spec, GpioIo does not have any polarity associated with it. Linux kernel
* uses `active_low` argument within GPIO _DSD property to allow BIOS to indicate if the
* corresponding GPIO should be treated as active low. Thus, if the GPIO has active high
* polarity or if it does not have any polarity, then the `active_low` argument is
* supposed to be set to 0.
*
* Reference:
* https://www.kernel.org/doc/html/latest/firmware-guide/acpi/gpio-properties.html
*/
bool active_low;
};
/* GpioIo-related macros */
#define ACPI_GPIO_CFG(_gpio, _io_restrict, _active_low) { \
.type = ACPI_GPIO_TYPE_IO, \
.pull = ACPI_GPIO_PULL_DEFAULT, \
.io_restrict = _io_restrict, \
.active_low = _active_low, \
.pin_count = 1, \
.pins = { (_gpio) } }
/* Basic output GPIO with default pull settings */
#define ACPI_GPIO_OUTPUT_CFG(gpio, active_low) \
ACPI_GPIO_CFG(gpio, ACPI_GPIO_IO_RESTRICT_OUTPUT, active_low)
#define ACPI_GPIO_OUTPUT(gpio) ACPI_GPIO_OUTPUT_CFG(gpio, 0)
#define ACPI_GPIO_OUTPUT_ACTIVE_HIGH(gpio) ACPI_GPIO_OUTPUT_CFG(gpio, 0)
#define ACPI_GPIO_OUTPUT_ACTIVE_LOW(gpio) ACPI_GPIO_OUTPUT_CFG(gpio, 1)
/* Basic input GPIO with default pull settings */
#define ACPI_GPIO_INPUT_CFG(gpio, polarity) \
ACPI_GPIO_CFG(gpio, ACPI_GPIO_IO_RESTRICT_INPUT, polarity)
#define ACPI_GPIO_INPUT(gpio) ACPI_GPIO_INPUT_CFG(gpio, 0)
#define ACPI_GPIO_INPUT_ACTIVE_HIGH(gpio) ACPI_GPIO_INPUT_CFG(gpio, 0)
#define ACPI_GPIO_INPUT_ACTIVE_LOW(gpio) ACPI_GPIO_INPUT_CFG(gpio, 1)
/* GpioInt-related macros */
#define ACPI_GPIO_IRQ_CFG(_gpio, _mode, _polarity, _wake) { \
.type = ACPI_GPIO_TYPE_INTERRUPT, \
.pull = ACPI_GPIO_PULL_DEFAULT, \
.irq.mode = _mode, \
.irq.polarity = _polarity, \
.irq.wake = _wake, \
.pin_count = 1, \
.pins = { (_gpio) } }
#define ACPI_GPIO_IRQ_EDGE(gpio, polarity) \
ACPI_GPIO_IRQ_CFG(gpio, ACPI_IRQ_EDGE_TRIGGERED, polarity, 0)
#define ACPI_GPIO_IRQ_EDGE_WAKE(gpio, polarity) \
ACPI_GPIO_IRQ_CFG(gpio, ACPI_IRQ_EDGE_TRIGGERED, polarity, ACPI_IRQ_WAKE)
#define ACPI_GPIO_IRQ_LEVEL(gpio, polarity) \
ACPI_GPIO_IRQ_CFG(gpio, ACPI_IRQ_LEVEL_TRIGGERED, polarity, 0)
#define ACPI_GPIO_IRQ_LEVEL_WAKE(gpio, polarity) \
ACPI_GPIO_IRQ_CFG(gpio, ACPI_IRQ_LEVEL_TRIGGERED, polarity, ACPI_IRQ_WAKE)
/* Edge Triggered Active High GPIO interrupt */
#define ACPI_GPIO_IRQ_EDGE_HIGH(gpio) \
ACPI_GPIO_IRQ_EDGE(gpio, ACPI_IRQ_ACTIVE_HIGH)
/* Edge Triggered Active Low GPIO interrupt */
#define ACPI_GPIO_IRQ_EDGE_LOW(gpio) \
ACPI_GPIO_IRQ_EDGE(gpio, ACPI_IRQ_ACTIVE_LOW)
/* Edge Triggered Active Both GPIO interrupt */
#define ACPI_GPIO_IRQ_EDGE_BOTH(gpio) \
ACPI_GPIO_IRQ_EDGE(gpio, ACPI_IRQ_ACTIVE_BOTH)
/* Edge Triggered Active High GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_EDGE_HIGH_WAKE(gpio) \
ACPI_GPIO_IRQ_EDGE_WAKE(gpio, ACPI_IRQ_ACTIVE_HIGH)
/* Edge Triggered Active Low GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_EDGE_LOW_WAKE(gpio) \
ACPI_GPIO_IRQ_EDGE_WAKE(gpio, ACPI_IRQ_ACTIVE_LOW)
/* Edge Triggered Active Both GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_EDGE_BOTH_WAKE(gpio) \
ACPI_GPIO_IRQ_EDGE_WAKE(gpio, ACPI_IRQ_ACTIVE_BOTH)
/* Level Triggered Active High GPIO interrupt */
#define ACPI_GPIO_IRQ_LEVEL_HIGH(gpio) \
ACPI_GPIO_IRQ_LEVEL(gpio, ACPI_IRQ_ACTIVE_HIGH)
/* Level Triggered Active Low GPIO interrupt */
#define ACPI_GPIO_IRQ_LEVEL_LOW(gpio) \
ACPI_GPIO_IRQ_LEVEL(gpio, ACPI_IRQ_ACTIVE_LOW)
/* Level Triggered Active High GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_LEVEL_HIGH_WAKE(gpio) \
ACPI_GPIO_IRQ_LEVEL_WAKE(gpio, ACPI_IRQ_ACTIVE_HIGH)
/* Level Triggered Active Low GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_LEVEL_LOW_WAKE(gpio) \
ACPI_GPIO_IRQ_LEVEL_WAKE(gpio, ACPI_IRQ_ACTIVE_LOW)
/* Write GpioIo() or GpioInt() descriptor to SSDT AML output */
void acpi_device_write_gpio(const struct acpi_gpio *gpio);
/*
* ACPI Descriptors for Serial Bus interfaces
*/
#define ACPI_SERIAL_BUS_TYPE_I2C 1
#define ACPI_SERIAL_BUS_TYPE_SPI 2
#define ACPI_SERIAL_BUS_TYPE_UART 3
#define ACPI_I2C_SERIAL_BUS_REVISION_ID 1 /* TODO: upgrade to 2 */
#define ACPI_I2C_TYPE_SPECIFIC_REVISION_ID 1
#define ACPI_SPI_SERIAL_BUS_REVISION_ID 1
#define ACPI_SPI_TYPE_SPECIFIC_REVISION_ID 1
#define ACPI_UART_SERIAL_BUS_REVISION_ID 1
#define ACPI_UART_TYPE_SPECIFIC_REVISION_ID 1
/*
* ACPI I2C Bus
*/
struct acpi_i2c {
/* I2C Address */
uint16_t address;
/* 7 or 10 bit Address Mode */
enum i2c_address_mode mode_10bit;
/* I2C Bus Speed in Hz */
enum i2c_speed speed;
/* Reference to I2C controller */
const char *resource;
};
/* Write I2cSerialBus() descriptor to SSDT AML output */
void acpi_device_write_i2c(const struct acpi_i2c *i2c);
/*
* ACPI SPI Bus
*/
struct acpi_spi {
/* Device selection */
uint16_t device_select;
/* Device selection line is active high or low */
enum spi_polarity device_select_polarity;
/* 3 or 4 wire SPI connection */
enum spi_wire_mode wire_mode;
/* Connection speed in HZ */
unsigned int speed;
/* Size in bits of smallest transfer unit */
u8 data_bit_length;
/* Phase of clock pulse on which to capture data */
enum spi_clock_phase clock_phase;
/* Indicate if clock is high or low during first phase */
enum spi_polarity clock_polarity;
/* Reference to SPI controller */
const char *resource;
};
/* Write SPI Bus descriptor to SSDT AML output */
void acpi_device_write_spi(const struct acpi_spi *spi);
/*
* ACPI UART Bus
*/
enum acpi_uart_data_bits {
ACPI_UART_DATA_BITS_5,
ACPI_UART_DATA_BITS_6,
ACPI_UART_DATA_BITS_7,
ACPI_UART_DATA_BITS_8,
ACPI_UART_DATA_BITS_9
};
enum acpi_uart_stop_bits {
ACPI_UART_STOP_BITS_0,
ACPI_UART_STOP_BITS_1,
ACPI_UART_STOP_BITS_1_5,
ACPI_UART_STOP_BITS_2
};
enum acpi_uart_lines {
ACPI_UART_LINE_DTD = BIT(2), /* Data Carrier Detect */
ACPI_UART_LINE_RI = BIT(3), /* Ring Indicator */
ACPI_UART_LINE_DSR = BIT(4), /* Data Set Ready */
ACPI_UART_LINE_DTR = BIT(5), /* Data Terminal Ready */
ACPI_UART_LINE_CTS = BIT(6), /* Clear to Send */
ACPI_UART_LINE_RTS = BIT(7) /* Request to Send */
};
enum acpi_uart_endian {
ACPI_UART_ENDIAN_LITTLE,
ACPI_UART_ENDIAN_BIG
};
enum acpi_uart_parity {
ACPI_UART_PARITY_NONE,
ACPI_UART_PARITY_EVEN,
ACPI_UART_PARITY_ODD,
ACPI_UART_PARITY_MARK,
ACPI_UART_PARITY_SPACE
};
enum acpi_uart_flow_control {
ACPI_UART_FLOW_NONE,
ACPI_UART_FLOW_HARDWARE,
ACPI_UART_FLOW_SOFTWARE
};
struct acpi_uart {
/* Initial Baud Rate in bits per second */
uint32_t initial_baud_rate;
/* Number of bits of data in a packet (value between 5-9) */
enum acpi_uart_data_bits data_bits;
/* Number of bits to signal end of packet */
enum acpi_uart_stop_bits stop_bits;
/* Bitmask indicating presence or absence of particular line */
unsigned int lines_in_use;
/* Specify if the device expects big or little endian format */
enum acpi_uart_endian endian;
/* Specify the type of parity bits included after the data in a packet */
enum acpi_uart_parity parity;
/* Specify the flow control method */
enum acpi_uart_flow_control flow_control;
/* Upper limit in bytes of the buffer sizes for this device */
uint16_t rx_fifo_bytes;
uint16_t tx_fifo_bytes;
/* Set true if UART is shared, false if it is exclusive for one device */
bool shared;
/* Reference to UART controller */
const char *resource;
};
#define ACPI_UART_RAW_DEVICE(baud_rate, fifo_bytes) { \
.initial_baud_rate = (baud_rate), \
.data_bits = ACPI_UART_DATA_BITS_8, \
.stop_bits = ACPI_UART_STOP_BITS_1, \
.endian = ACPI_UART_ENDIAN_LITTLE, \
.parity = ACPI_UART_PARITY_NONE, \
.flow_control = ACPI_UART_FLOW_NONE, \
.rx_fifo_bytes = (fifo_bytes), \
.tx_fifo_bytes = (fifo_bytes), \
.shared = false }
/* Write UARTSerialBusV2() descriptor to SSDT AML output */
void acpi_device_write_uart(const struct acpi_uart *uart);
/* GPIO/timing information for the power on/off sequences */
struct acpi_power_res_params {
/* GPIO used to take device out of reset or to put it into reset. */
struct acpi_gpio *reset_gpio;
/* Delay to be inserted after device is taken out of reset.
* (_ON method delay)
*/
unsigned int reset_delay_ms;
/* Delay to be inserted after device is put into reset.
* (_OFF method delay)
*/
unsigned int reset_off_delay_ms;
/* GPIO used to enable device. */
struct acpi_gpio *enable_gpio;
/* Delay to be inserted after device is enabled.
* (_ON method delay)
*/
unsigned int enable_delay_ms;
/* Delay to be inserted after device is disabled.
* (_OFF method delay)
*/
unsigned int enable_off_delay_ms;
/* GPIO used to stop operation of device. */
struct acpi_gpio *stop_gpio;
/* Delay to be inserted after disabling stop.
* (_ON method delay)
*/
unsigned int stop_delay_ms;
/* Delay to be inserted after enabling stop.
* (_OFF method delay)
*/
unsigned int stop_off_delay_ms;
/* Write a _STA method that uses the state of the GPIOs to determine if
* the PowerResource is ON or OFF. If this is false, the _STA method
* will always return ON.
*/
bool use_gpio_for_status;
};
/*
* Add a basic PowerResource block for a device that includes
* GPIOs to control enable, reset and stop operation of the device. Each
* GPIO is optional, but at least one must be provided.
*
* Reset - Put the device into / take the device out of reset.
* Enable - Enable / disable power to device.
* Stop - Stop / start operation of device.
*/
void acpi_device_add_power_res(const struct acpi_power_res_params *params);
/*
* 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 new Device Property table with provided ACPI reference */
struct acpi_dp *acpi_dp_new_table(const char *ref);
/* Add package of device properties with a unique UUID */
struct acpi_dp *acpi_dp_add_package(struct acpi_dp *dp, struct acpi_dp *package);
/* Add integer Device Property */
struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
uint64_t value);
/* Add string Device Property */
struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
const char *string);
/* Add ACPI reference Device Property */
struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
const char *reference);
/* Add an array of Device Properties */
struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array);
/* Add an array of integers Device Property */
struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
const uint64_t *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);
struct acpi_gpio_res_params {
/* Reference to the parent device. */
const char *ref;
/* Index to the GpioIo resource within the _CRS. */
int index;
/* Index to the pin within the GpioIo resource, usually 0. */
int pin;
/* Flag to indicate if pin is active low. */
int active_low;
};
/* Add a GPIO binding device property for array of GPIOs */
struct acpi_dp *acpi_dp_add_gpio_array(struct acpi_dp *dp, const char *name,
const struct acpi_gpio_res_params *params,
size_t param_count);
/* 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);
/* Add a list of Device Properties, returns the number of properties added */
size_t acpi_dp_add_property_list(struct acpi_dp *dp,
const struct acpi_dp *property_list,
size_t property_count);
/* Write Device Property hierarchy and clean up resources */
void acpi_dp_write(struct acpi_dp *table);
/*
* Helper function to write a PCI device with _ADR object defined.
*
* IMPORTANT: Scope of a device created in SSDT cannot be used to add ACPI nodes under that
* scope in DSDT. So, if there are any references to this PCI device scope required from static
* asl files, do not use this function and instead add the device to DSDT as well.
*/
void acpi_device_write_pci_dev(const struct device *dev);
#endif /* __ACPI_ACPI_DEVICE_H__ */