soc/intel/xeon_sp: Create CXL domains

SPR CXL IIO stack is divided into 2 PCI domains. The 1st domain
is a PCI domain with single bus number and PCIe RCiEPs (Root
Complex Integrated End Points) on it. The 2nd domain is a CXL
domain with remaining buses for CXL 1.0/1.1 end points and
possible SR-IOV (Single Root IO Virtualizaton) VFs (Virtual
Function) if any.

TEST=intel/archercity CRB

P.S. The SUT is not with CXL cards however we hope this refactor
could be integrated first as an improvement of the design.

Change-Id: I643bcfbae7b6e8cfe11c147cc89374bc6b4d5a80
Signed-off-by: Shuo Liu <shuo.liu@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/81099
Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/soc/intel/xeon_sp/chip_common.c b/src/soc/intel/xeon_sp/chip_common.c
index 93949c8..67c1089 100644
--- a/src/soc/intel/xeon_sp/chip_common.c
+++ b/src/soc/intel/xeon_sp/chip_common.c
@@ -176,32 +176,32 @@
 #endif
 };
 
-static void soc_create_pcie_domains(const union xeon_domain_path dp, struct bus *upstream,
-				const STACK_RES *sr)
+static void soc_create_domains(const union xeon_domain_path dp, struct bus *upstream,
+				int bus_base, int bus_limit, const char *type,
+				struct device_operations *ops)
 {
-	union xeon_domain_path new_path = {
-		.domain_path = dp.domain_path
-	};
-	new_path.bus = sr->BusBase;
-
-	struct device_path path = {
-		.type = DEVICE_PATH_DOMAIN,
-		.domain = {
-			.domain = new_path.domain_path,
-		},
-	};
+	struct device_path path;
+	init_xeon_domain_path(&path, dp.socket, dp.stack, bus_base);
 
 	struct device *const domain = alloc_find_dev(upstream, &path);
 	if (!domain)
 		die("%s: out of memory.\n", __func__);
 
-	domain->ops = &iio_pcie_domain_ops;
-	iio_domain_set_acpi_name(domain, DOMAIN_TYPE_PCIE);
+	domain->ops = ops;
+	iio_domain_set_acpi_name(domain, type);
 
 	struct bus *const bus = alloc_bus(domain);
-	bus->secondary = sr->BusBase;
-	bus->subordinate = sr->BusBase;
-	bus->max_subordinate = sr->BusLimit;
+	bus->secondary = bus_base;
+	bus->subordinate = bus_base;
+	bus->max_subordinate = bus_limit;
+}
+
+
+static void soc_create_pcie_domains(const union xeon_domain_path dp, struct bus *upstream,
+				const STACK_RES *sr)
+{
+	soc_create_domains(dp, upstream, sr->BusBase, sr->BusLimit, DOMAIN_TYPE_PCIE,
+				&iio_pcie_domain_ops);
 }
 
 /*
@@ -212,38 +212,74 @@
 static void soc_create_ubox_domains(const union xeon_domain_path dp, struct bus *upstream,
 				const STACK_RES *sr)
 {
-	union xeon_domain_path new_path = {
-		.domain_path = dp.domain_path
-	};
-
 	/* Only expect 2 UBOX buses here */
-	int bus_base = sr->BusBase;
-	int bus_limit = sr->BusLimit;
-	assert(bus_base + 1 == bus_limit);
-	for (int i = bus_base; i <= bus_limit; i++) {
-		new_path.bus = i;
+	assert(sr->BusBase + 1 == sr->BusLimit);
 
-		struct device_path path = {
-			.type = DEVICE_PATH_DOMAIN,
-			.domain = {
-				.domain = new_path.domain_path,
-			},
-		};
-		struct device *const domain = alloc_find_dev(upstream, &path);
-		if (!domain)
-			die("%s: out of memory.\n", __func__);
+	soc_create_domains(dp, upstream, sr->BusBase, sr->BusBase, DOMAIN_TYPE_UBX0,
+				&ubox_pcie_domain_ops);
+	soc_create_domains(dp, upstream, sr->BusLimit, sr->BusLimit, DOMAIN_TYPE_UBX1,
+				&ubox_pcie_domain_ops);
+}
 
-		domain->ops = &ubox_pcie_domain_ops;
-		const char *prefix = (i == bus_base) ? DOMAIN_TYPE_UBX0 : DOMAIN_TYPE_UBX1;
-		iio_domain_set_acpi_name(domain, prefix);
+#if CONFIG(SOC_INTEL_HAS_CXL)
+void iio_cxl_domain_read_resources(struct device *dev)
+{
+	struct resource *res;
+	const STACK_RES *sr = domain_to_stack_res(dev);
 
-		struct bus *const bus = alloc_bus(domain);
-		bus->secondary = i;
-		bus->subordinate = bus->secondary;
-		bus->max_subordinate = bus->secondary;
+	if (!sr)
+		return;
+
+	int index = 0;
+
+	if (sr->IoBase < sr->PciResourceIoBase) {
+		res = new_resource(dev, index++);
+		res->base = sr->IoBase;
+		res->limit = sr->PciResourceIoBase - 1;
+		res->size = res->limit - res->base + 1;
+		res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED;
+	}
+
+	if (sr->Mmio32Base < sr->PciResourceMem32Base) {
+		res = new_resource(dev, index++);
+		res->base = sr->Mmio32Base;
+		res->limit = sr->PciResourceMem32Base - 1;
+		res->size = res->limit - res->base + 1;
+		res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED;
+	}
+
+	if (sr->Mmio64Base < sr->PciResourceMem64Base) {
+		res = new_resource(dev, index++);
+		res->base = sr->Mmio64Base;
+		res->limit = sr->PciResourceMem64Base - 1;
+		res->size = res->limit - res->base + 1;
+		res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED;
 	}
 }
 
+static struct device_operations iio_cxl_domain_ops = {
+	.read_resources = iio_cxl_domain_read_resources,
+	.set_resources = pci_domain_set_resources,
+	.scan_bus = pci_host_bridge_scan_bus,
+#if CONFIG(HAVE_ACPI_TABLES)
+	.acpi_name        = soc_acpi_name,
+	.write_acpi_tables = northbridge_write_acpi_tables,
+#endif
+};
+
+void soc_create_cxl_domains(const union xeon_domain_path dp, struct bus *bus,
+				const STACK_RES *sr)
+{
+	assert(sr->BusBase + 1 <= sr->BusLimit);
+	/* 1st domain contains PCIe RCiEPs */
+	soc_create_domains(dp, bus, sr->BusBase, sr->BusBase, DOMAIN_TYPE_PCIE,
+				&iio_pcie_domain_ops);
+	/* 2nd domain contains CXL 1.1 end-points */
+	soc_create_domains(dp, bus, sr->BusBase + 1, sr->BusLimit, DOMAIN_TYPE_CXL,
+				&iio_cxl_domain_ops);
+}
+#endif //CONFIG(SOC_INTEL_HAS_CXL)
+
 /* Attach stack as domains */
 void attach_iio_stacks(void)
 {
@@ -265,6 +301,8 @@
 
 			if (is_ubox_stack_res(ri))
 				soc_create_ubox_domains(dn, root_bus, ri);
+			else if (CONFIG(SOC_INTEL_HAS_CXL) && is_iio_cxl_stack_res(ri))
+				soc_create_cxl_domains(dn, root_bus, ri);
 			else if (is_pcie_iio_stack_res(ri))
 				soc_create_pcie_domains(dn, root_bus, ri);
 			else if (CONFIG(HAVE_IOAT_DOMAINS) && is_ioat_iio_stack_res(ri))
diff --git a/src/soc/intel/xeon_sp/include/soc/chip_common.h b/src/soc/intel/xeon_sp/include/soc/chip_common.h
index 47dea8e..bcfdf62 100644
--- a/src/soc/intel/xeon_sp/include/soc/chip_common.h
+++ b/src/soc/intel/xeon_sp/include/soc/chip_common.h
@@ -3,6 +3,7 @@
 #ifndef _CHIP_COMMON_H_
 #define _CHIP_COMMON_H_
 
+#include <device/path.h>
 #include <hob_iiouds.h>
 
 union xeon_domain_path {
@@ -15,6 +16,19 @@
 	};
 };
 
+
+static inline void init_xeon_domain_path(struct device_path *path, int socket,
+	int stack, int bus)
+{
+	union xeon_domain_path dp = {
+		.socket = socket,
+		.stack = stack,
+		.bus = bus,
+	};
+	path->type = DEVICE_PATH_DOMAIN;
+	path->domain.domain = dp.domain_path;
+};
+
 /*
  * Every STACK can have multiple PCI domains with an unique domain type.
  * This is only of cosmetic nature and generates more readable ACPI code,
@@ -28,11 +42,14 @@
 #define DOMAIN_TYPE_PCIE       "PC"
 #define DOMAIN_TYPE_UBX0       "UC"
 #define DOMAIN_TYPE_UBX1       "UD"
+#define DOMAIN_TYPE_CXL        "CX"
 
 void iio_pci_domain_read_resources(struct device *dev);
+void iio_cxl_domain_read_resources(struct device *dev);
 void attach_iio_stacks(void);
 
 void soc_create_ioat_domains(union xeon_domain_path path, struct bus *bus, const STACK_RES *sr);
+void soc_create_cxl_domains(const union xeon_domain_path dp, struct bus *bus, const STACK_RES *sr);
 struct device *dev_find_device_on_socket(uint8_t socket, u16 vendor, u16 device);
 int iio_pci_domain_socket_from_dev(struct device *dev);
 int iio_pci_domain_stack_from_dev(struct device *dev);
diff --git a/src/soc/intel/xeon_sp/include/soc/util.h b/src/soc/intel/xeon_sp/include/soc/util.h
index a7d5dac..db66fcb 100644
--- a/src/soc/intel/xeon_sp/include/soc/util.h
+++ b/src/soc/intel/xeon_sp/include/soc/util.h
@@ -32,6 +32,7 @@
 bool is_pcie_iio_stack_res(const STACK_RES *res);
 bool is_ubox_stack_res(const STACK_RES *res);
 bool is_ioat_iio_stack_res(const STACK_RES *res);
+bool is_iio_cxl_stack_res(const STACK_RES *res);
 void bios_done_msr(void *unused);
 
 #endif
diff --git a/src/soc/intel/xeon_sp/spr/include/soc/soc_util.h b/src/soc/intel/xeon_sp/spr/include/soc/soc_util.h
index 631601e..bf81f3d 100644
--- a/src/soc/intel/xeon_sp/spr/include/soc/soc_util.h
+++ b/src/soc/intel/xeon_sp/spr/include/soc/soc_util.h
@@ -31,8 +31,6 @@
 const struct SystemMemoryMapHob *get_system_memory_map(void);
 const struct SystemMemoryMapElement *get_system_memory_map_elment(uint8_t *num);
 
-bool is_iio_cxl_stack_res(const STACK_RES *res);
-
 void soc_display_iio_universal_data_hob(const IIO_UDS *hob);
 void soc_display_memmap_hob(const struct SystemMemoryMapHob **hob_addr);