acpi: Add support for writing UART device descriptors

This change adds support for generating the device descriptor that
corresponds to the UARTSerialBusV2() ACPI macro.

The resulting ACPI code for ACPI_UART_RAW_DEVICE(115200, 64) is:

UartSerialBusV2 (0x0001C200, DataBitsEight, StopBitsOne,
                 0x00, LittleEndian, ParityTypeNone, FlowControlNone,
                 0x0040, 0x0040, "\\_SB.PCI0.UAR2",
                 0x00, ResourceConsumer, , Exclusive)

Change-Id: I671ce2a499d74717d8677528c46ab3fbc1d7faf5
Signed-off-by: Duncan Laurie <dlaurie@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41792
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
diff --git a/src/acpi/device.c b/src/acpi/device.c
index 9e8efa4..9ce86eb 100644
--- a/src/acpi/device.c
+++ b/src/acpi/device.c
@@ -523,6 +523,80 @@
 	acpi_device_fill_len(desc_length);
 }
 
+/* UART Serial Bus - UARTSerialBusV2() */
+void acpi_device_write_uart(const struct acpi_uart *uart)
+{
+	void *desc_length, *type_length;
+	uint16_t flags;
+
+	/* Byte 0: Descriptor Type */
+	acpigen_emit_byte(ACPI_DESCRIPTOR_SERIAL_BUS);
+
+	/* Byte 1+2: Length (filled in later) */
+	desc_length = acpi_device_write_zero_len();
+
+	/* Byte 3: Revision ID */
+	acpigen_emit_byte(ACPI_UART_SERIAL_BUS_REVISION_ID);
+
+	/* Byte 4: Resource Source Index is Reserved */
+	acpigen_emit_byte(0);
+
+	/* Byte 5: Serial Bus Type is UART */
+	acpigen_emit_byte(ACPI_SERIAL_BUS_TYPE_UART);
+
+	/*
+	 * Byte 6: Flags
+	 *  [7:2]: 0 => Reserved
+	 *    [1]: 1 => ResourceConsumer
+	 *    [0]: 0 => ControllerInitiated
+	 */
+	acpigen_emit_byte(BIT(1));
+
+	/*
+	 * Byte 7-8: Type Specific Flags
+	 *   [15:8]: 0 => Reserved
+	 *      [7]: 0 => Little Endian, 1 => Big Endian
+	 *    [6:4]: Data bits
+	 *    [3:2]: Stop bits
+	 *    [1:0]: Flow control
+	 */
+	flags = uart->flow_control & 3;
+	flags |= (uart->stop_bits & 3) << 2;
+	flags |= (uart->data_bits & 7) << 4;
+	flags |= (uart->endian & 1) << 7;
+	acpigen_emit_word(flags);
+
+	/* Byte 9: Type Specific Revision ID */
+	acpigen_emit_byte(ACPI_UART_TYPE_SPECIFIC_REVISION_ID);
+
+	/* Byte 10-11: Type Data Length */
+	type_length = acpi_device_write_zero_len();
+
+	/* Byte 12-15: Initial Baud Rate */
+	acpigen_emit_dword(uart->initial_baud_rate);
+
+	/* Byte 16-17: RX FIFO size */
+	acpigen_emit_word(uart->rx_fifo_bytes);
+
+	/* Byte 18-19: TX FIFO size */
+	acpigen_emit_word(uart->tx_fifo_bytes);
+
+	/* Byte 20: Parity */
+	acpigen_emit_byte(uart->parity);
+
+	/* Byte 21: Lines Enabled */
+	acpigen_emit_byte(uart->lines_in_use);
+
+	/* Fill in Type Data Length */
+	acpi_device_fill_len(type_length);
+
+	/* Byte 22+: ResourceSource */
+	acpigen_emit_string(uart->resource);
+
+	/* Fill in Descriptor Length */
+	acpi_device_fill_len(desc_length);
+}
+
 /* PowerResource() with Enable and/or Reset control */
 void acpi_device_add_power_res(const struct acpi_power_res_params *params)
 {
diff --git a/src/include/acpi/acpi_device.h b/src/include/acpi/acpi_device.h
index 2c2c67a..8cf36e3 100644
--- a/src/include/acpi/acpi_device.h
+++ b/src/include/acpi/acpi_device.h
@@ -323,10 +323,14 @@
 
 #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
@@ -372,6 +376,91 @@
 /* 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. */