drivers/intel/pmc_mux/con: Add new PMC MUX & CON chip drivers

The Tiger Lake PMC device has a MUX device which is expected to be
exposed in ACPI tables. The MUX device simply has a _HID and _DDN.

The CON devices link the USB-2 and USB-3 port numbers (from SoC
point of view) to the physical connector. They also have orientation
options for the sideband (SBU) and USB High Speed signals (HSL),
meaning that they can be fixed (i.e, another device besides the SoC
controls the orientation, and effectively the SoC is following only
CC1 or CC2 orientation), or they can follow the CC lines.

BUG=b:151646486
TEST=Tested with next patch in series (see TEST line there)

Change-Id: I8b5f275907601960410459aa669e257b80ff3dc2
Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Signed-off-by: John Zhao <john.zhao@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40862
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
diff --git a/src/drivers/intel/pmc_mux/con/con.c b/src/drivers/intel/pmc_mux/con/con.c
new file mode 100644
index 0000000..08c38e8
--- /dev/null
+++ b/src/drivers/intel/pmc_mux/con/con.c
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <acpi/acpigen.h>
+#include <console/console.h>
+#include <intelblocks/acpi.h>
+#include "chip.h"
+
+static const char *con_acpi_name(const struct device *dev)
+{
+	static char name[5];
+	snprintf(name, sizeof(name), "CON%1X", dev->path.generic.id);
+	return name;
+}
+
+static const char *orientation_to_str(enum typec_orientation ori)
+{
+	switch (ori) {
+	case TYPEC_ORIENTATION_NORMAL:
+		return "normal";
+	case TYPEC_ORIENTATION_REVERSE:
+		return "reverse";
+	case TYPEC_ORIENTATION_FOLLOW_CC: /* Intentional fallthrough */
+	default:
+		return "";
+	}
+}
+
+static void con_fill_ssdt(const struct device *dev)
+{
+	struct drivers_intel_pmc_mux_con_config *config = dev->chip_info;
+	struct acpi_dp *dsd;
+
+	if (!dev->enabled)
+		return;
+
+	/* Reference the existing scope and write CONx device */
+	acpigen_write_scope(acpi_device_scope(dev));
+	acpigen_write_device(acpi_device_name(dev));
+
+	acpigen_write_name_integer("_ADR", dev->path.generic.id);
+
+	/* _DSD, Device-Specific Data */
+	dsd = acpi_dp_new_table("_DSD");
+	acpi_dp_add_integer(dsd, "usb2-port-number", config->usb2_port_number);
+	acpi_dp_add_integer(dsd, "usb3-port-number", config->usb3_port_number);
+
+	/*
+	 * The kernel assumes that these Type-C signals (SBUs and HSLs) follow the CC lines,
+	 * unless they are explicitly called out otherwise.
+	 */
+	if (config->sbu_orientation != TYPEC_ORIENTATION_FOLLOW_CC)
+		acpi_dp_add_string(dsd, "sbu-orientation",
+				   orientation_to_str(config->sbu_orientation));
+
+	if (config->hsl_orientation != TYPEC_ORIENTATION_FOLLOW_CC)
+		acpi_dp_add_string(dsd, "hsl-orientation",
+				   orientation_to_str(config->hsl_orientation));
+
+	acpi_dp_write(dsd);
+
+	acpigen_pop_len(); /* CONx Device */
+	acpigen_pop_len(); /* Scope */
+
+	printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name,
+	       dev_path(dev));
+}
+
+static struct device_operations con_dev_ops = {
+	.read_resources	= noop_read_resources,
+	.set_resources	= noop_set_resources,
+	.acpi_name	= con_acpi_name,
+	.acpi_fill_ssdt	= con_fill_ssdt,
+};
+
+static void con_enable(struct device *dev)
+{
+	dev->ops = &con_dev_ops;
+}
+
+struct chip_operations drivers_intel_pmc_mux_con_ops = {
+	CHIP_NAME("Intel PMC MUX CON Driver")
+	.enable_dev	= con_enable,
+};