From 3e7197a59edfb13c0dc8ffe47a67d744c7132c2a Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Mon, 7 May 2018 14:18:13 -0700 Subject: [PATCH] acpi: Add support for writing ACPI _PLD structures This commit adds support for writing ACPI _PLD structures that describe the physical location of a device to the OS. This can be used by any device with a physical connector, but is required when defining USB ports for the OS. A simple function is provided that generates a generic _PLD structure for USB ports based on the USB port type. Change-Id: Ic9cf1fd158eca80ead21b4725b37ab3c36b000f3 Signed-off-by: Duncan Laurie Reviewed-on: https://review.coreboot.org/26171 Tested-by: build bot (Jenkins) Reviewed-by: Furquan Shaikh Reviewed-by: Paul Menzel --- src/arch/x86/Makefile.inc | 1 + src/arch/x86/acpi_pld.c | 169 +++++++++++++++++++++++++++ src/arch/x86/acpigen.c | 11 ++ src/arch/x86/include/arch/acpi_pld.h | 120 +++++++++++++++++++ src/arch/x86/include/arch/acpigen.h | 2 + 5 files changed, 303 insertions(+) create mode 100644 src/arch/x86/acpi_pld.c create mode 100644 src/arch/x86/include/arch/acpi_pld.h diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc index f94e5478be..54ce9b0e4a 100644 --- a/src/arch/x86/Makefile.inc +++ b/src/arch/x86/Makefile.inc @@ -328,6 +328,7 @@ ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpigen.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpigen_dsm.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi_device.c +ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi_pld.c ramstage-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.c ramstage-y += boot.c ramstage-y += c_start.S diff --git a/src/arch/x86/acpi_pld.c b/src/arch/x86/acpi_pld.c new file mode 100644 index 0000000000..d399ea69dd --- /dev/null +++ b/src/arch/x86/acpi_pld.c @@ -0,0 +1,169 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Google LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +int acpi_pld_fill_usb(struct acpi_pld *pld, enum acpi_upc_type type) +{ + if (!pld) + return -1; + + memset(pld, 0, sizeof(struct acpi_pld)); + + /* Set defaults */ + pld->ignore_color = 1; + pld->panel = PLD_PANEL_UNKNOWN; + pld->vertical_position = PLD_VERTICAL_POSITION_CENTER; + pld->horizontal_position = PLD_HORIZONTAL_POSITION_CENTER; + pld->rotation = PLD_ROTATE_0; + pld->visible = 1; + + /* Set the shape based on port type */ + switch (type) { + case UPC_TYPE_A: + case UPC_TYPE_USB3_A: + case UPC_TYPE_USB3_POWER_B: + pld->shape = PLD_SHAPE_HORIZONTAL_RECTANGLE; + break; + case UPC_TYPE_MINI_AB: + case UPC_TYPE_USB3_B: + pld->shape = PLD_SHAPE_CHAMFERED; + break; + case UPC_TYPE_USB3_MICRO_B: + case UPC_TYPE_USB3_MICRO_AB: + pld->shape = PLD_SHAPE_HORIZONTAL_TRAPEZOID; + break; + case UPC_TYPE_C_USB2_ONLY: + case UPC_TYPE_C_USB2_SS_SWITCH: + case UPC_TYPE_C_USB2_SS: + pld->shape = PLD_SHAPE_OVAL; + break; + case UPC_TYPE_INTERNAL: + default: + pld->shape = PLD_SHAPE_UNKNOWN; + pld->visible = 0; + break; + } + + return 0; +} + +int acpi_pld_to_buffer(const struct acpi_pld *pld, uint8_t *buf, int buf_len) +{ + if (!pld || !buf) + return -1; + + memset(buf, 0, buf_len); + + /* [0] Revision (=2) */ + buf[0] = 0x2; + + if (pld->ignore_color) { + /* [1] Ignore Color */ + buf[0] |= 0x80; + } else { + /* [15:8] Red Color */ + buf[1] = pld->color_red; + /* [23:16] Green Color */ + buf[2] = pld->color_green; + /* [31:24] Blue Color */ + buf[3] = pld->color_blue; + } + + /* [47:32] Width */ + buf[4] = pld->width & 0xff; + buf[5] = pld->width >> 8; + + /* [63:48] Height */ + buf[6] = pld->height & 0xff; + buf[7] = pld->height >> 8; + + /* [64] User Visible */ + buf[8] |= (pld->visible & 0x1); + + /* [65] Dock */ + buf[8] |= (pld->dock & 0x1) << 1; + + /* [66] Lid */ + buf[8] |= (pld->lid & 0x1) << 2; + + /* [69:67] Panel */ + buf[8] |= (pld->panel & 0x7) << 3; + + /* [71:70] Vertical Position */ + buf[8] |= (pld->vertical_position & 0x3) << 6; + + /* [73:72] Horizontal Position */ + buf[9] |= (pld->horizontal_position & 0x3); + + /* [77:74] Shape */ + buf[9] |= (pld->shape & 0xf) << 2; + + /* [78] Group Orientation */ + buf[9] |= (pld->group_orientation & 0x1) << 6; + + /* [86:79] Group Token (incorrectly defined as 1 bit in ACPI 6.2A) */ + buf[9] |= (pld->group_token & 0x1) << 7; + buf[10] |= (pld->group_token >> 0x1) & 0x7f; + + /* [94:87] Group Position */ + buf[10] |= (pld->group_position & 0x1) << 7; + buf[11] |= (pld->group_position >> 0x1) & 0x7f; + + /* [95] Bay */ + buf[11] |= (pld->bay & 0x1) << 7; + + /* [96] Ejectable */ + buf[12] |= (pld->ejectable & 0x1); + + /* [97] Ejectable with OSPM help */ + buf[12] |= (pld->ejectable_ospm & 0x1) << 1; + + /* [105:98] Cabinet Number */ + buf[12] |= (pld->cabinet_number & 0x3f) << 2; + buf[13] |= (pld->cabinet_number >> 6) & 0x3; + + /* [113:106] Card Cage Number */ + buf[13] |= (pld->card_cage_number & 0x3f) << 2; + buf[14] |= (pld->card_cage_number >> 6) & 0x3; + + /* [114] PLD is a Reference Shape */ + buf[14] |= (pld->reference_shape & 0x1) << 2; + + /* [118:115] Rotation */ + buf[14] |= (pld->rotation & 0xf) << 3; + + /* [123:119] Draw Order */ + buf[14] |= (pld->draw_order & 0x1) << 7; + buf[15] |= (pld->draw_order >> 1) & 0xf; + + /* [127:124] Reserved */ + + /* Both 16 byte and 20 byte buffers are supported by the spec */ + if (buf_len == 20) { + /* [143:128] Vertical Offset */ + buf[16] = pld->vertical_offset & 0xff; + buf[17] = pld->vertical_offset >> 8; + + /* [159:144] Horizontal Offset */ + buf[18] = pld->horizontal_offset & 0xff; + buf[19] = pld->horizontal_offset >> 8; + } + + return 0; +} diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c index 867c809a45..6243d265ce 100644 --- a/src/arch/x86/acpigen.c +++ b/src/arch/x86/acpigen.c @@ -1236,6 +1236,17 @@ void acpigen_write_upc(enum acpi_upc_type type) acpigen_pop_len(); } +void acpigen_write_pld(const struct acpi_pld *pld) +{ + uint8_t buf[20]; + + if (acpi_pld_to_buffer(pld, buf, ARRAY_SIZE(buf)) < 0) + return; + + acpigen_write_name("_PLD"); + acpigen_write_byte_buffer(buf, ARRAY_SIZE(buf)); +} + void acpigen_write_dsm(const char *uuid, void (**callbacks)(void *), size_t count, void *arg) { diff --git a/src/arch/x86/include/arch/acpi_pld.h b/src/arch/x86/include/arch/acpi_pld.h new file mode 100644 index 0000000000..ce279a00d5 --- /dev/null +++ b/src/arch/x86/include/arch/acpi_pld.h @@ -0,0 +1,120 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2018 Google LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ACPI_PLD_H +#define __ACPI_PLD_H + +#include +#include + +enum acpi_pld_panel { + PLD_PANEL_TOP, + PLD_PANEL_BOTTOM, + PLD_PANEL_LEFT, + PLD_PANEL_RIGHT, + PLD_PANEL_FRONT, + PLD_PANEL_BACK, + PLD_PANEL_UNKNOWN +}; + +enum acpi_pld_vertical_position { + PLD_VERTICAL_POSITION_UPPER, + PLD_VERTICAL_POSITION_CENTER, + PLD_VERTICAL_POSITION_LOWER +}; + +/* + * The ACPI spec 6.2A does not define the horizontal position field. + * These values are taken from the IASL compiler: + * https://github.com/acpica/acpica/blob/master/source/components/utilities/utglobal.c#L321 + */ + +enum acpi_pld_horizontal_position { + PLD_HORIZONTAL_POSITION_LEFT, + PLD_HORIZONTAL_POSITION_CENTER, + PLD_HORIZONTAL_POSITION_RIGHT +}; + +enum acpi_pld_shape { + PLD_SHAPE_ROUND, + PLD_SHAPE_OVAL, + PLD_SHAPE_SQUARE, + PLD_SHAPE_VERTICAL_RECTANGLE, + PLD_SHAPE_HORIZONTAL_RECTANGLE, + PLD_SHAPE_VERTICAL_TRAPEZOID, + PLD_SHAPE_HORIZONTAL_TRAPEZOID, + PLD_SHAPE_UNKNOWN, + PLD_SHAPE_CHAMFERED +}; + +enum acpi_pld_orientation { + PLD_ORIENTATION_HORIZONTAL, + PLD_ORIENTATION_VERTICAL, +}; + +enum acpi_pld_rotate { + PLD_ROTATE_0, + PLD_ROTATE_45, + PLD_ROTATE_90, + PLD_ROTATE_135, + PLD_ROTATE_180, + PLD_ROTATE_225, + PLD_ROTATE_270, + PLD_ROTATE_315 +}; + +struct acpi_pld { + /* Color field can be explicitly ignored */ + bool ignore_color; + uint8_t color_red; + uint8_t color_blue; + uint8_t color_green; + + /* Port characteristics */ + bool visible; /* Can be seen by the user */ + bool lid; /* Port is on lid of device */ + bool dock; /* Port is in a docking station */ + bool bay; /* Port is in a bay */ + bool ejectable; /* Device is ejectable, has _EJx objects */ + bool ejectable_ospm; /* Device needs OSPM to eject */ + uint16_t width; /* Width in mm */ + uint16_t height; /* Height in mm */ + uint16_t vertical_offset; + uint16_t horizontal_offset; + enum acpi_pld_panel panel; + enum acpi_pld_horizontal_position horizontal_position; + enum acpi_pld_vertical_position vertical_position; + enum acpi_pld_shape shape; + enum acpi_pld_rotate rotation; + + /* Port grouping */ + enum acpi_pld_orientation group_orientation; + uint8_t group_token; + uint8_t group_position; + uint8_t draw_order; + uint8_t cabinet_number; + uint8_t card_cage_number; + + /* Set if this PLD defines a reference shape */ + bool reference_shape; +}; + +/* Fill out PLD structure with defaults based on USB port type */ +int acpi_pld_fill_usb(struct acpi_pld *pld, enum acpi_upc_type type); + +/* Turn PLD structure into a 20 byte ACPI buffer */ +int acpi_pld_to_buffer(const struct acpi_pld *pld, uint8_t *buf, int buf_len); + +#endif diff --git a/src/arch/x86/include/arch/acpigen.h b/src/arch/x86/include/arch/acpigen.h index 250c0b73c9..52aa55b6b8 100644 --- a/src/arch/x86/include/arch/acpigen.h +++ b/src/arch/x86/include/arch/acpigen.h @@ -23,6 +23,7 @@ #include #include #include +#include /* Values that can be returned for ACPI Device _STA method */ #define ACPI_STATUS_DEVICE_PRESENT (1 << 0) @@ -256,6 +257,7 @@ void acpigen_write_return_byte_buffer(uint8_t *arr, size_t size); void acpigen_write_return_singleton_buffer(uint8_t arg); void acpigen_write_return_byte(uint8_t arg); void acpigen_write_upc(enum acpi_upc_type type); +void acpigen_write_pld(const struct acpi_pld *pld); /* * Generate ACPI AML code for _DSM method. * This function takes as input uuid for the device, set of callbacks and