acpi: Add new file for implementing Type-C Connector class
The USB Type-C Connector Class in the Linux kernel is not specific to the ChromeOS EC, so this functionality is now split out into a separate file, acpigen_usb.c. Documentation about the kernel side is available at https://www.kernel.org/doc/html/latest/driver-api/usb/typec.html. Change-Id: Ife5b8b517b261e7c0068c862ea65039c20382c5a Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/41539 Reviewed-by: Duncan Laurie <dlaurie@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
6046739b9d
commit
92d96e84c4
|
@ -6,6 +6,7 @@ ramstage-y += acpi.c
|
||||||
ramstage-y += acpigen.c
|
ramstage-y += acpigen.c
|
||||||
ramstage-y += acpigen_dsm.c
|
ramstage-y += acpigen_dsm.c
|
||||||
ramstage-y += acpigen_ps2_keybd.c
|
ramstage-y += acpigen_ps2_keybd.c
|
||||||
|
ramstage-y += acpigen_usb.c
|
||||||
ramstage-y += device.c
|
ramstage-y += device.c
|
||||||
ramstage-y += pld.c
|
ramstage-y += pld.c
|
||||||
ramstage-y += sata.c
|
ramstage-y += sata.c
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include <acpi/acpi.h>
|
||||||
|
#include <acpi/acpi_device.h>
|
||||||
|
#include <acpi/acpigen.h>
|
||||||
|
#include <acpi/acpigen_usb.h>
|
||||||
|
|
||||||
|
static const char *power_role_to_str(enum usb_typec_power_role power_role)
|
||||||
|
{
|
||||||
|
switch (power_role) {
|
||||||
|
case TYPEC_POWER_ROLE_SOURCE:
|
||||||
|
return "source";
|
||||||
|
case TYPEC_POWER_ROLE_SINK:
|
||||||
|
return "sink";
|
||||||
|
case TYPEC_POWER_ROLE_DUAL:
|
||||||
|
return "dual";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *try_power_role_to_str(enum usb_typec_try_power_role try_power_role)
|
||||||
|
{
|
||||||
|
switch (try_power_role) {
|
||||||
|
case TYPEC_TRY_POWER_ROLE_NONE:
|
||||||
|
/*
|
||||||
|
* This should never get returned; if there is no try-power role for a device,
|
||||||
|
* then the try-power-role field is not added to the DSD. Thus, this is just
|
||||||
|
* for completeness.
|
||||||
|
*/
|
||||||
|
return "none";
|
||||||
|
case TYPEC_TRY_POWER_ROLE_SINK:
|
||||||
|
return "sink";
|
||||||
|
case TYPEC_TRY_POWER_ROLE_SOURCE:
|
||||||
|
return "source";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *data_role_to_str(enum usb_typec_data_role data_role)
|
||||||
|
{
|
||||||
|
switch (data_role) {
|
||||||
|
case TYPEC_DATA_ROLE_DFP:
|
||||||
|
return "host";
|
||||||
|
case TYPEC_DATA_ROLE_UFP:
|
||||||
|
return "device";
|
||||||
|
case TYPEC_DATA_ROLE_DUAL:
|
||||||
|
return "dual";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add port capabilities as DP properties */
|
||||||
|
static void add_port_caps(struct acpi_dp *dsd,
|
||||||
|
const struct typec_connector_class_config *config)
|
||||||
|
{
|
||||||
|
acpi_dp_add_string(dsd, "power-role", power_role_to_str(config->power_role));
|
||||||
|
acpi_dp_add_string(dsd, "data-role", data_role_to_str(config->data_role));
|
||||||
|
|
||||||
|
if (config->try_power_role != TYPEC_TRY_POWER_ROLE_NONE)
|
||||||
|
acpi_dp_add_string(dsd, "try-power-role",
|
||||||
|
try_power_role_to_str(config->try_power_role));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_device_ref(struct acpi_dp *dsd,
|
||||||
|
const char *prop_name,
|
||||||
|
const struct device *dev)
|
||||||
|
{
|
||||||
|
const char *path;
|
||||||
|
char *fresh;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unfortunately, the acpi_dp_* API doesn't write out the data immediately, thus we need
|
||||||
|
* different storage areas for all of the strings, so strdup() is used for that. It is
|
||||||
|
* safe to use strdup() here, because the strings are generated at build-time and are
|
||||||
|
* guaranteed to be NUL-terminated (they come from the devicetree).
|
||||||
|
*/
|
||||||
|
path = acpi_device_path(dev);
|
||||||
|
if (path) {
|
||||||
|
fresh = strdup(path);
|
||||||
|
if (fresh)
|
||||||
|
acpi_dp_add_reference(dsd, prop_name, fresh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_device_references(struct acpi_dp *dsd,
|
||||||
|
const struct typec_connector_class_config *config)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Add references to the USB port objects so that the consumer of this information can
|
||||||
|
* know whether the port supports USB2, USB3, and/or USB4.
|
||||||
|
*/
|
||||||
|
add_device_ref(dsd, "usb2-port", config->usb2_port);
|
||||||
|
add_device_ref(dsd, "usb3-port", config->usb3_port);
|
||||||
|
add_device_ref(dsd, "usb4-port", config->usb4_port);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add references to the ACPI device(s) which control the orientation, USB data role and
|
||||||
|
* data muxing.
|
||||||
|
*/
|
||||||
|
add_device_ref(dsd, "orientation-switch", config->orientation_switch);
|
||||||
|
add_device_ref(dsd, "usb-role-switch", config->usb_role_switch);
|
||||||
|
add_device_ref(dsd, "mode-switch", config->mode_switch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpigen_write_typec_connector(const struct typec_connector_class_config *config,
|
||||||
|
int port_number,
|
||||||
|
add_custom_dsd_property_cb add_custom_dsd_property)
|
||||||
|
{
|
||||||
|
struct acpi_dp *dsd;
|
||||||
|
char name[5];
|
||||||
|
|
||||||
|
/* Create a CONx device */
|
||||||
|
snprintf(name, sizeof(name), "CON%1X", port_number);
|
||||||
|
acpigen_write_device(name);
|
||||||
|
acpigen_write_name_integer("_ADR", port_number);
|
||||||
|
|
||||||
|
dsd = acpi_dp_new_table("_DSD");
|
||||||
|
|
||||||
|
/* Write out the _DSD table */
|
||||||
|
acpi_dp_add_integer(dsd, "port-number", port_number);
|
||||||
|
add_port_caps(dsd, config);
|
||||||
|
add_device_references(dsd, config);
|
||||||
|
|
||||||
|
/* Allow client to add custom properties if desired */
|
||||||
|
if (add_custom_dsd_property)
|
||||||
|
add_custom_dsd_property(dsd, port_number);
|
||||||
|
acpi_dp_write(dsd);
|
||||||
|
|
||||||
|
acpigen_pop_len(); /* Device */
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#ifndef ACPI_ACPIGEN_USB_H
|
||||||
|
#define ACPI_ACPIGEN_USB_H
|
||||||
|
|
||||||
|
enum usb_typec_power_role {
|
||||||
|
TYPEC_POWER_ROLE_SOURCE,
|
||||||
|
TYPEC_POWER_ROLE_SINK,
|
||||||
|
TYPEC_POWER_ROLE_DUAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum usb_typec_try_power_role {
|
||||||
|
TYPEC_TRY_POWER_ROLE_NONE,
|
||||||
|
TYPEC_TRY_POWER_ROLE_SINK,
|
||||||
|
TYPEC_TRY_POWER_ROLE_SOURCE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum usb_typec_data_role {
|
||||||
|
TYPEC_DATA_ROLE_DFP,
|
||||||
|
TYPEC_DATA_ROLE_UFP,
|
||||||
|
TYPEC_DATA_ROLE_DUAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration required to write out a Type-C Connector ACPI object.
|
||||||
|
*
|
||||||
|
* @power_role: DUAL if device supports being both a source and a sink, otherwise choose
|
||||||
|
* the device's default power role
|
||||||
|
* @try_power_role: SINK if device supports Try.SNK, SOURCE if device supports Try.SRC,
|
||||||
|
* otherwise choose NONE
|
||||||
|
* @data_role: Choose DUAL if device can alternate between UFP (host) & DFP (device),
|
||||||
|
* otherwise specify UFP or DFP.
|
||||||
|
* @usb2_port: Reference to the ACPI device that represents the USB2 signals
|
||||||
|
* @usb3_port: Reference to the ACPI device that represents the USB3 signals
|
||||||
|
* @usb4_port: Reference to the ACPI device that represents the USB4 signals
|
||||||
|
* @orientation_switch: Reference to the ACPI device that controls the switching of
|
||||||
|
* the orientation/polarity for Data and SBU lines.
|
||||||
|
* @usb_role_switch: Reference to the ACPI device that can select the USB role,
|
||||||
|
* host or device, for the USB port
|
||||||
|
* @mode_switch: Reference to the ACPI device that controls routing of data lines to
|
||||||
|
* various endpoints (xHCI, DP, etc.) on the SoC.
|
||||||
|
*/
|
||||||
|
struct typec_connector_class_config {
|
||||||
|
enum usb_typec_power_role power_role;
|
||||||
|
enum usb_typec_try_power_role try_power_role;
|
||||||
|
enum usb_typec_data_role data_role;
|
||||||
|
const struct device *usb2_port;
|
||||||
|
const struct device *usb3_port;
|
||||||
|
const struct device *usb4_port;
|
||||||
|
const struct device *orientation_switch;
|
||||||
|
const struct device *usb_role_switch;
|
||||||
|
const struct device *mode_switch;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*add_custom_dsd_property_cb)(struct acpi_dp *dsd, int port_number);
|
||||||
|
|
||||||
|
void acpigen_write_typec_connector(const struct typec_connector_class_config *config,
|
||||||
|
int port_number,
|
||||||
|
add_custom_dsd_property_cb add_custom_dsd_property);
|
||||||
|
|
||||||
|
#endif /* ACPI_ACPIGEN_USB_H */
|
Loading…
Reference in New Issue