feat(qemu-sbsa): handle memory information

As a part of removing DeviceTree from EDK2, we move functions to TF-A:

- counting the number of memory nodes
- checking NUMA node id
- checking the memory address

Signed-off-by: Xiong Yining <xiongyining1480@phytium.com.cn>
Signed-off-by: Chen Baozi <chenbaozi@phytium.com.cn>
Change-Id: Ib7bce3a65c817a5b3bef6c9e0a459c7ce76c7e35
diff --git a/plat/qemu/qemu_sbsa/include/platform_def.h b/plat/qemu/qemu_sbsa/include/platform_def.h
index 14030e3..e8f0344 100644
--- a/plat/qemu/qemu_sbsa/include/platform_def.h
+++ b/plat/qemu/qemu_sbsa/include/platform_def.h
@@ -62,6 +62,11 @@
 #define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
 
 /*
+ * Define the max number of memory nodes.
+ */
+#define PLAT_MAX_MEM_NODES	128
+
+/*
  * Partition memory into secure ROM, non-secure DRAM, secure "SRAM",
  * and secure DRAM.
  */
diff --git a/plat/qemu/qemu_sbsa/sbsa_sip_svc.c b/plat/qemu/qemu_sbsa/sbsa_sip_svc.c
index ed49e91..535f0eb 100644
--- a/plat/qemu/qemu_sbsa/sbsa_sip_svc.c
+++ b/plat/qemu/qemu_sbsa/sbsa_sip_svc.c
@@ -30,6 +30,8 @@
 #define SIP_SVC_GET_GIC_ITS SIP_FUNCTION_ID(101)
 #define SIP_SVC_GET_CPU_COUNT SIP_FUNCTION_ID(200)
 #define SIP_SVC_GET_CPU_NODE SIP_FUNCTION_ID(201)
+#define SIP_SVC_GET_MEMORY_NODE_COUNT SIP_FUNCTION_ID(300)
+#define SIP_SVC_GET_MEMORY_NODE SIP_FUNCTION_ID(301)
 
 static uint64_t gic_its_addr;
 
@@ -38,9 +40,17 @@
 	uint32_t mpidr;
 } cpu_data;
 
+typedef struct{
+	uint32_t nodeid;
+	uint64_t addr_base;
+	uint64_t addr_size;
+} memory_data;
+
 static struct {
 	uint32_t num_cpus;
+	uint32_t num_memnodes;
 	cpu_data cpu[PLATFORM_CORE_COUNT];
+	memory_data memory[PLAT_MAX_MEM_NODES];
 } dynamic_platform_info;
 
 void sbsa_set_gic_bases(const uintptr_t gicd_base, const uintptr_t gicr_base);
@@ -127,6 +137,79 @@
 	INFO("Found %d cpus\n", dynamic_platform_info.num_cpus);
 }
 
+void read_meminfo_from_dt(void *dtb)
+{
+	const fdt32_t *prop;
+	const char *type;
+	int prev, node;
+	int len;
+	uint32_t nodeid = 0;
+	uint32_t memnode = 0;
+	uint32_t higher_value, lower_value;
+	uint64_t cur_base, cur_size;
+
+	/*
+	 * QEMU gives us this DeviceTree node:
+	 *
+	 *	memory@100c0000000 {
+	 *		numa-node-id = <0x01>;
+	 *		reg = <0x100 0xc0000000 0x00 0x40000000>;
+	 *		device_type = "memory";
+	 *	};
+	 *
+	 *	memory@10000000000 {
+	 *		numa-node-id = <0x00>;
+	 *		reg = <0x100 0x00 0x00 0xc0000000>;
+	 *		device_type = "memory";
+	 *	}
+	 */
+
+	for (prev = 0;; prev = node) {
+		node = fdt_next_node(dtb, prev, NULL);
+		if (node < 0) {
+			break;
+		}
+
+		type = fdt_getprop(dtb, node, "device_type", &len);
+		if (type && strncmp(type, "memory", len) == 0) {
+			if (fdt_getprop(dtb, node, "numa-node-id", NULL)) {
+				fdt_read_uint32(dtb, node, "numa-node-id", &nodeid);
+			}
+
+			dynamic_platform_info.memory[memnode].nodeid = nodeid;
+
+			/*
+			 * Get the 'reg' property of this node and
+			 * assume two 8 bytes for base and size.
+			 */
+			prop = fdt_getprop(dtb, node, "reg", &len);
+			if (prop != 0 && len == (2 * sizeof(int64_t))) {
+				higher_value = fdt32_to_cpu(*prop);
+				lower_value = fdt32_to_cpu(*(prop + 1));
+				cur_base = (uint64_t)(lower_value | ((uint64_t)higher_value) << 32);
+
+				higher_value = fdt32_to_cpu(*(prop + 2));
+				lower_value = fdt32_to_cpu(*(prop + 3));
+				cur_size = (uint64_t)(lower_value | ((uint64_t)higher_value) << 32);
+
+				dynamic_platform_info.memory[memnode].addr_base = cur_base;
+				dynamic_platform_info.memory[memnode].addr_size = cur_size;
+
+				INFO("RAM %d: node-id: %d, address: 0x%lx - 0x%lx\n",
+					memnode,
+					dynamic_platform_info.memory[memnode].nodeid,
+					dynamic_platform_info.memory[memnode].addr_base,
+					dynamic_platform_info.memory[memnode].addr_base +
+					dynamic_platform_info.memory[memnode].addr_size - 1);
+			}
+
+			memnode++;
+		}
+	}
+
+	dynamic_platform_info.num_memnodes = memnode;
+}
+
 void read_platform_config_from_dt(void *dtb)
 {
 	int node;
@@ -222,6 +305,7 @@
 
 	read_platform_config_from_dt(dtb);
 	read_cpuinfo_from_dt(dtb);
+	read_meminfo_from_dt(dtb);
 }
 
 /*
@@ -270,6 +354,20 @@
 			SMC_RET1(handle, SMC_ARCH_CALL_INVAL_PARAM);
 		}
 
+	case SIP_SVC_GET_MEMORY_NODE_COUNT:
+		SMC_RET2(handle, NULL, dynamic_platform_info.num_memnodes);
+
+	case SIP_SVC_GET_MEMORY_NODE:
+		index = x1;
+		if (index < PLAT_MAX_MEM_NODES) {
+			SMC_RET4(handle, NULL,
+				dynamic_platform_info.memory[index].nodeid,
+				dynamic_platform_info.memory[index].addr_base,
+				dynamic_platform_info.memory[index].addr_size);
+		} else {
+			SMC_RET1(handle, SMC_ARCH_CALL_INVAL_PARAM);
+		}
+
 	default:
 		ERROR("%s: unhandled SMC (0x%x) (function id: %d)\n", __func__, smc_fid,
 		      smc_fid - SIP_FUNCTION);