Add device tree fixup handler infrastructure to support runtime
modifications of board information, DDR configuration, and hardware
subset parts through the OF_LIVE interface.

This patch introduces three fixup handlers that modify the device tree
at runtime to provide platform-specific information from SMEM:

1. Board info fixup (qcom_fixup_boardinfo.c)
   - Adds board-specific information like serial number to the
     device tree

2. DDR info fixup (qcom_fixup_ddrinfo.c)
   - Adds DDR configuration information like DDR size & regions

3. Subset parts fixup (qcom_fixup_subsetparts.c)
   - Identifies & enables OS to adapt to available hardware subparts
     (GPU, video, camera, display, audio, modem, WLAN, compute,
     sensors, NPU, disabled CPU cores, etc.)

Supporting headers:
- qcom_fixup_handlers.h: Function prototypes and type definitions
- chipinfo_def.h: Chip identification and part definitions
- rampart.h: Platform-specific definitions

Signed-off-by: Aswin Murugan <[email protected]>
---
 arch/arm/mach-snapdragon/Makefile             |   3 +
 arch/arm/mach-snapdragon/chipinfo_def.h       |  90 ++++++
 .../mach-snapdragon/qcom_fixup_boardinfo.c    | 217 ++++++++++++++
 arch/arm/mach-snapdragon/qcom_fixup_ddrinfo.c | 214 +++++++++++++
 .../arm/mach-snapdragon/qcom_fixup_handlers.h |  70 +++++
 .../mach-snapdragon/qcom_fixup_subsetparts.c  | 281 ++++++++++++++++++
 arch/arm/mach-snapdragon/rampart.h            | 236 +++++++++++++++
 7 files changed, 1111 insertions(+)
 create mode 100644 arch/arm/mach-snapdragon/chipinfo_def.h
 create mode 100644 arch/arm/mach-snapdragon/qcom_fixup_boardinfo.c
 create mode 100644 arch/arm/mach-snapdragon/qcom_fixup_ddrinfo.c
 create mode 100644 arch/arm/mach-snapdragon/qcom_fixup_handlers.h
 create mode 100644 arch/arm/mach-snapdragon/qcom_fixup_subsetparts.c
 create mode 100644 arch/arm/mach-snapdragon/rampart.h

diff --git a/arch/arm/mach-snapdragon/Makefile 
b/arch/arm/mach-snapdragon/Makefile
index 343e825c6fd..62e390f2ca4 100644
--- a/arch/arm/mach-snapdragon/Makefile
+++ b/arch/arm/mach-snapdragon/Makefile
@@ -4,4 +4,7 @@
 
 obj-y += board.o
 obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o
+obj-$(CONFIG_OF_LIVE) += qcom_fixup_boardinfo.o
+obj-$(CONFIG_OF_LIVE) += qcom_fixup_ddrinfo.o
+obj-$(CONFIG_OF_LIVE) += qcom_fixup_subsetparts.o
 obj-$(CONFIG_OF_LIVE) += of_fixup.o
diff --git a/arch/arm/mach-snapdragon/chipinfo_def.h 
b/arch/arm/mach-snapdragon/chipinfo_def.h
new file mode 100644
index 00000000000..fc497da825c
--- /dev/null
+++ b/arch/arm/mach-snapdragon/chipinfo_def.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Type and enum definitions for the Chip Info driver
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+enum chip_info_result {
+       CHIPINFO_SUCCESS = 0,
+       CHIPINFO_ERROR = -1,
+       CHIPINFO_ERROR_INVALID_PARAMETER = -2,
+       CHIPINFO_ERROR_INSUFFICIENT_MEMORY = -3,
+       CHIPINFO_ERROR_NOT_FOUND = -4,
+       CHIPINFO_ERROR_INTERNAL = -5,
+       CHIPINFO_ERROR_NOT_ALLOWED = -6,
+       CHIPINFO_ERROR_NOT_SUPPORTED = -7,
+       CHIPINFO_ERROR_NOT_INITIALIZED = -8,
+       CHIPINFO_ERROR_OUT_OF_RANGE_PARAMETER = -9,
+       CHIPINFO_ERROR_INVALID_ADDRESS = -10,
+       CHIPINFO_ERROR_INSUFFICIENT_BUFFER_LENGTH = -11,
+};
+
+/**
+ * Supported parts by the chipinfo_get_disabled_features API.
+ * New parts should be appended to this enum (i.e. not inserted)
+ * to preserve backwards compatibility.
+ *
+ * For targets that have multiple instances of a specific part,
+ * a new part with a _N suffix should be added. On these targets,
+ * part enums without the _N suffix are for the 0th instance,
+ * e.g. CHIPINFO_PART_DISPLAY is for MDSS_0 on Makena.
+ */
+enum chip_info_Part_type {
+       CHIPINFO_PART_UNKNOWN = 0,
+       CHIPINFO_PART_GPU = 1,
+       CHIPINFO_PART_VIDEO = 2,
+       CHIPINFO_PART_CAMERA = 3,
+       CHIPINFO_PART_DISPLAY = 4,
+       CHIPINFO_PART_AUDIO = 5,
+       CHIPINFO_PART_MODEM = 6,
+       CHIPINFO_PART_WLAN = 7,
+       CHIPINFO_PART_COMP = 8, // For both CDSP and NSP
+       CHIPINFO_PART_SENSORS = 9,
+       CHIPINFO_PART_NPU = 10,
+       CHIPINFO_PART_SPSS = 11,
+       CHIPINFO_PART_NAV = 12,
+       CHIPINFO_PART_COMPUTE_1 = 13,
+       CHIPINFO_PART_DISPLAY_1 = 14,
+       CHIPINFO_PART_NSP = 15,
+       CHIPINFO_PART_EVA = 16,
+       CHIPINFO_PART_PCIE = 17,
+       CHIPINFO_PART_CPU = 18,
+       CHIPINFO_PART_DDR = 19,
+
+       CHIPINFO_NUM_PARTS,
+       CHIPINFO_PART_32BITS = 0x7FFFFFFF
+};
+
+/**
+ * SKU_IDs logical mapping.
+ * See ChipInfo_GetSKU for more details.
+ */
+enum chip_info_skuid_type {
+       CHIPINFO_SKU_UNKNOWN = 0,
+
+       CHIPINFO_SKU_AA = 0x01,
+       CHIPINFO_SKU_AB = 0x02,
+       CHIPINFO_SKU_AC = 0x03,
+       CHIPINFO_SKU_AD = 0x04,
+       CHIPINFO_SKU_AE = 0x05,
+       CHIPINFO_SKU_AF = 0x06,
+       // Reserved for future use
+
+       CHIPINFO_SKU_Y0 = 0xf1,
+       CHIPINFO_SKU_Y1 = 0xf2,
+       CHIPINFO_SKU_Y2 = 0xf3,
+       CHIPINFO_SKU_Y3 = 0xf4,
+       CHIPINFO_SKU_Y4 = 0xf5,
+       CHIPINFO_SKU_Y5 = 0xf6,
+       CHIPINFO_SKU_Y6 = 0xf7,
+       CHIPINFO_SKU_Y7 = 0xf8,
+       // Reserved for future use
+
+};
+
diff --git a/arch/arm/mach-snapdragon/qcom_fixup_boardinfo.c 
b/arch/arm/mach-snapdragon/qcom_fixup_boardinfo.c
new file mode 100644
index 00000000000..67a0aeccbb0
--- /dev/null
+++ b/arch/arm/mach-snapdragon/qcom_fixup_boardinfo.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Board Info FDT Fixup
+ *
+ * Copyright (c) 2015-2018, 2020-2021, The Linux Foundation. All rights 
reserved.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * This file contains code to fix up the device tree blob (DTB) for the board.
+ * It is responsible for adding or modifying nodes, properties, and values as
+ * necessary to ensure the DTB is in a valid state for the board.
+ *
+ * The fixups are applied in the following order:
+ * 1. Add any necessary nodes or properties
+ * 2. Modify existing nodes or properties
+ * 3. Remove any unnecessary nodes or properties
+ *
+ * Each fixup is documented with a comment explaining its purpose and any
+ * relevant details.
+ */
+
+#include <dm.h>
+#include <fdt_support.h>
+#include <smem.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/libfdt.h>
+#include <soc/qcom/socinfo.h>
+#include "chipinfo_def.h"
+#include "qcom_fixup_handlers.h"
+#include "qcom-priv.h"
+
+static const char *const feature_code_names_external[] = {
+       [CHIPINFO_SKU_UNKNOWN] = "Unknown",
+       [CHIPINFO_SKU_AA] = "AA",
+       [CHIPINFO_SKU_AB] = "AB",
+       [CHIPINFO_SKU_AC] = "AC",
+       [CHIPINFO_SKU_AD] = "AD",
+       [CHIPINFO_SKU_AE] = "AE",
+       [CHIPINFO_SKU_AF] = "AF",
+};
+
+static int add_serialnum_platinfo_prop(void *fdt_ptr, u32 node_offset);
+static int add_sku_prop(void *fdt_ptr, u32 node_offset);
+static int add_platforminfo_node(void *fdt_ptr);
+static void add_platforminfo_properties(void *fdt_ptr);
+
+/**
+ * board_serial_num() - Retrieves the board serial number from the SMEM.
+ * @serial_num_ptr: Pointer to a u32 variable to store the board
+ * serial number.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int board_serial_num(u32 *serial_num_ptr)
+{
+       struct socinfo *soc_info_ptr;
+
+       soc_info_ptr = qcom_get_socinfo();
+       if (!soc_info_ptr)
+               return log_msg_ret("Error: Failed to get socinfo\n", -1);
+
+       *serial_num_ptr = soc_info_ptr->serial_num;
+
+       return 0;
+}
+
+/**
+ * add_serialnum_platinfo_prop() - Adds the serial number property to the 
platform information node.
+ * @fdt_ptr: Pointer to the device tree.
+ * @node_offset: Offset of the platform information node in the device tree.
+ *
+ * This function adds the serial number property to the platform information
+ * node in the device tree. The serial number is retrieved from the SMEM using
+ * the board_serial_num function.
+ *
+ * Return: 0 on success, negative on failure.
+ */
+static int add_serialnum_platinfo_prop(void *fdt_ptr, u32 node_offset)
+{
+       u32 serial_num;
+       int ret;
+
+       ret = board_serial_num(&serial_num);
+       if (ret)
+               return log_msg_ret("ERROR: Could not find serial number to 
populate\n",
+                                  ret);
+       log_debug("Serial Number: 0x%x\n", serial_num);
+
+       ret = fixup_dt_node(fdt_ptr, node_offset, "serial-number",
+                           (void *)&serial_num, SET_PROP_U32);
+       if (ret)
+               log_err("ERROR: Cannot update Platform info node with 
SerialNumber - %d\n",
+                       ret);
+
+       return ret;
+}
+
+static int add_sku_prop(void *fdt_ptr, u32 node_offset)
+{
+       u32 pcode;
+       char feature_code[24];
+       int ret;
+       static const char feature_code_prop[] = "feature-code";
+       struct socinfo *soc_info_ptr;
+
+       soc_info_ptr = qcom_get_socinfo();
+       if (!soc_info_ptr)
+               return log_msg_ret("Error: Failed to get socinfo\n", -1);
+
+       strlcpy(feature_code,
+               feature_code_names_external[soc_info_ptr->feature_code],
+               sizeof(feature_code));
+       if (soc_info_ptr->pcode == 0)
+               pcode = 0xFFFFFFFF;
+       else
+               pcode = soc_info_ptr->pcode;
+
+       ret = fixup_dt_node(fdt_ptr, node_offset, "pcode", (void *)&pcode,
+                           SET_PROP_U32);
+       if (ret)
+               return log_msg_ret("ERROR: Cannot update Platform info node 
with Pcode\n",
+                                  ret);
+       ret = fixup_dt_node(fdt_ptr, node_offset, feature_code_prop,
+                           (void *)feature_code, SET_PROP_STRING);
+       if (ret)
+               log_err("ERROR: Cannot update Platform info node with feature 
code - %d\n",
+                       ret);
+
+       return ret;
+}
+
+/**
+ * add_platforminfo_node() - Adds the platform info node to the device tree.
+ * @fdt_ptr: The device tree to add the platform info node to.
+ *
+ * This function adds the platform info node to the device tree, including the
+ * serial number, SKU information, and other relevant properties.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int add_platforminfo_node(void *fdt_ptr)
+{
+       int node_offset;
+
+       node_offset = fdt_path_offset(fdt_ptr, 
"/firmware/qcom,platform-parts-info");
+       if (node_offset >= 0)
+               return node_offset;
+
+       node_offset = fdt_path_offset(fdt_ptr, "/firmware");
+       if (node_offset < 0) {
+               node_offset = fixup_dt_node(fdt_ptr, 0, "firmware", NULL,
+                                           ADD_SUBNODE);
+               if (node_offset < 0)
+                       return log_msg_ret("Error creating firmware node\n",
+                                          node_offset);
+       }
+
+       node_offset = fixup_dt_node(fdt_ptr, node_offset, 
"qcom,platform-parts-info",
+                                   NULL, ADD_SUBNODE);
+       if (node_offset < 0) {
+               log_err("Error adding qcom,platform-parts-info, Error: %d\n",
+                       node_offset);
+               node_offset = fdt_path_offset(fdt_ptr,
+                                             
"/firmware/qcom,platform-parts-info");
+               if (node_offset < 0)
+                       log_err("Retry getting qcom,platform-parts-info offset, 
Error: %d\n",
+                               node_offset);
+       }
+
+       return node_offset;
+}
+
+/**
+ * add_platforminfo_properties() - Adds platform information properties to the 
device tree.
+ * @fdt_ptr: The device tree to update.
+ *
+ * This function populates the device tree with platform information 
properties,
+ * including the serial number, SKU information, and platform parts 
information.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static void add_platforminfo_properties(void *fdt_ptr)
+{
+       int ret = 0;
+       int node_offset;
+
+       node_offset = add_platforminfo_node(fdt_ptr);
+       if (node_offset < 0) {
+               log_err("Failed to add qcom,platform-parts-info\n");
+               return;
+       }
+
+       ret = add_serialnum_platinfo_prop(fdt_ptr, node_offset);
+       if (ret)
+               log_err("Failed to add Serial Number property\n");
+
+       ret = add_sku_prop(fdt_ptr, node_offset);
+       if (ret)
+               log_err("Failed to add SKU properties\n");
+}
+
+/**
+ * boardinfo_fixup_handler() - Board info fixup handler.
+ * @fdt_ptr: Pointer to the device tree.
+ *
+ * This function is called to fix up the device tree blob (DTB) for the board.
+ * It adds or modifies nodes, properties, and values as necessary to ensure the
+ * DTB is in a valid state for the board.
+ */
+void boardinfo_fixup_handler(struct fdt_header *fdt_ptr)
+{
+       add_platforminfo_properties(fdt_ptr);
+}
diff --git a/arch/arm/mach-snapdragon/qcom_fixup_ddrinfo.c 
b/arch/arm/mach-snapdragon/qcom_fixup_ddrinfo.c
new file mode 100644
index 00000000000..99d2d12ac33
--- /dev/null
+++ b/arch/arm/mach-snapdragon/qcom_fixup_ddrinfo.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DDRInfo Fixup
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ */
+
+#include <dm.h>
+#include <fdt_support.h>
+#include <smem.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/libfdt.h>
+#include "qcom_fixup_handlers.h"
+#include "rampart.h"
+
+/* With the new SMEM architecture, SMEM IDs need to be defined in individual
+ * driver files
+ */
+#define SMEM_ID_DDRINFO 0x25B // 603
+#define MAX_IDX_CH 8
+
+struct ddr_freq_table {
+       u32 freq_khz;
+       u8 enable;
+};
+
+struct ddr_freq_plan_entry {
+       struct ddr_freq_table ddr_freq[14];
+       u8 num_ddr_freqs;
+       u32 *clk_period_address;
+       u32 max_nom_ddr_freq;
+};
+
+struct ddr_part_details {
+       u8 revision_id1[2];
+       u8 revision_id2[2];
+       u8 width[2];
+       u8 density[2];
+};
+
+struct ddr_details_entry {
+       u8 manufacturer_id;
+       u8 device_type;
+       struct ddr_part_details ddr_params[MAX_IDX_CH];
+       struct ddr_freq_plan_entry ddr_freq_tbl;
+       u8 num_channels;
+       u8 num_ranks[2]; /* number of ranks per channel */
+       u8 hbb[2][2];
+       /* Highest Bank Bit per rank per channel */ /*Reserved for Future use*/
+};
+
+static int get_ddr_details(struct ddr_details_entry *ddr_detail);
+
+/**
+ * get_ddr_details() - Retrieves the DDR details entry from the SMEM.
+ * @ddr_detail: The DDR details entry to retrieve.
+ *
+ * This function retrieves the DDR details entry from the SMEM and prints it
+ * out.
+ *
+ * Return: 0 on success, -1 on failure
+ */
+static int get_ddr_details(struct ddr_details_entry *ddr_detail)
+{
+       void *ddr_table_ptr;
+       struct udevice *dev;
+       size_t size;
+
+       if (uclass_get_device(UCLASS_SMEM, 0, &dev) != 0)
+               return log_msg_ret("Error: uclass_get_device\n", -1);
+       ddr_table_ptr = smem_get(dev, 0, SMEM_ID_DDRINFO, &size);
+
+       if (!ddr_table_ptr)
+               return log_msg_ret("Error: invalid DDR Entry\n", -1);
+       memcpy((void *)ddr_detail, ddr_table_ptr, sizeof(struct 
ddr_details_entry));
+
+       return 0;
+}
+
+/**
+ * set_mem_reg_node() - Sets the ram partition info to memory node
+ * @fdt_ptr: Pointer to the device tree
+ * @path_offset: Offset to the memory node
+ * @start_addr: Start address of the mem partition
+ * @mem_size: Size of the mem partition
+ *
+ * This function is responsible for setting the reg property of memory node
+ * in the device tree
+ *
+ * Return: 0 on success, -1 on failure
+ */
+static int set_mem_reg_node(struct fdt_header *fdt_ptr, u32 path_offset,
+                           u64 start_addr, u64 mem_size)
+{
+       int ret;
+
+       log_debug("Mem info start addr: %llx ,size %llx\n", start_addr, 
mem_size);
+       ret = fixup_dt_node(fdt_ptr, path_offset, "reg",
+                           (void *)(&start_addr), APPEND_PROP_U64);
+       if (ret)
+               return log_msg_ret("Failed to append start_addr details in Reg 
prop\n", -1);
+
+       ret = fixup_dt_node(fdt_ptr, path_offset, "reg",
+                           (void *)(&mem_size), APPEND_PROP_U64);
+       if (ret)
+               return log_msg_ret("Failed to append mem_size details in Reg 
prop\n", -1);
+
+       return 0;
+}
+
+/**
+ * set_ram_part_info() - Gets the ram partition info from smem and sets
+ * it to memory node
+ * @fdt_ptr: Pointer to the device tree
+ * @path_offset: Offset to the memory node
+ *
+ * This function is responsible for obtaining ram partition information info
+ * from smem and sets it to the device tree
+ * tree.
+ *
+ * Return: 0 on success, -1 on failure
+ */
+static int set_ram_part_info(struct fdt_header *fdt_ptr, u32 path_offset)
+{
+       int ret = 0, res, part;
+       size_t size;
+       struct udevice *dev;
+       struct usable_ram_partition_table *rpt;
+       struct ram_partition_entry *rpe;
+
+       uclass_get_device(UCLASS_SMEM, 0, &dev);
+       rpt = smem_get(dev, 0, SMEM_USABLE_RAM_PARTITION_TABLE, &size);
+       if (!rpt)
+               return -1;
+       rpe = &rpt->ram_part_entry[0];
+
+       for (part = 0; part < rpt->num_partitions; part++, rpe++)
+               if (rpe->partition_category == RAM_PARTITION_SDRAM &&
+                   rpe->partition_type == RAM_PARTITION_SYS_MEMORY) {
+                       res = set_mem_reg_node(fdt_ptr, path_offset,
+                                              rpe->start_address,
+                                              rpe->available_length);
+                       if (res) {
+                               log_err("Failed to set Mem info start addr: 
%llx ,size %llx\n",
+                                       rpe->start_address, 
rpe->available_length);
+                               ret = -1;
+                       }
+               }
+
+       return ret;
+}
+
+/**
+ * ddrinfo_fixup_handler() - DDRInfo Fixup handler function
+ * @fdt_ptr: Pointer to the device tree
+ *
+ * This function is responsible for updating the DDR information in the device
+ * tree.
+ */
+void ddrinfo_fixup_handler(struct fdt_header *fdt_ptr)
+{
+       u32 path_offset, chan, ret;
+       u64 prop_value;
+       char fdt_rank_prop[] = "ddr_device_rank_ch  ";
+       struct ddr_details_entry ddr_details;
+
+       ret = get_ddr_details(&ddr_details);
+       if (ret) {
+               log_err("Error getting DDR details\n");
+               return;
+       }
+
+       path_offset = fdt_path_offset(fdt_ptr, "/memory");
+       if (path_offset < 0) {
+               log_err("Error getting memory offset: %d\n", path_offset);
+               return;
+       }
+       prop_value = (u64)ddr_details.device_type;
+       ret = fixup_dt_node(fdt_ptr, path_offset, "ddr_device_type",
+                           (void *)(&prop_value), APPEND_PROP_U64);
+       if (ret)
+               log_err("Failed to append DDR device type data : %d\n", ret);
+
+       prop_value = (u64)ddr_details.num_channels;
+       ret = fixup_dt_node(fdt_ptr, path_offset, "ddr_device_channel",
+                           (void *)(&prop_value), APPEND_PROP_U64);
+       if (ret)
+               log_err("Failed to append DDR Channels data : %d\n", ret);
+
+       for (chan = 0; chan < ddr_details.num_channels; chan++) {
+               snprintf(fdt_rank_prop, sizeof(fdt_rank_prop),
+                        "ddr_device_rank_ch%d", chan);
+               prop_value = (u64)ddr_details.num_ranks[chan];
+               ret = fixup_dt_node(fdt_ptr, path_offset,
+                                   (const char *)fdt_rank_prop,
+                                   (void *)(&prop_value),
+                                   APPEND_PROP_U64);
+               if (ret)
+                       log_err("Failed to append DDR ranks data : %d\n", ret);
+       }
+       ret = fdt_delprop(fdt_ptr, path_offset, "reg");
+       if (!ret) {
+               ret = set_ram_part_info(fdt_ptr, path_offset);
+               if (ret)
+                       log_err("set_ram_part_info failed");
+       }
+}
+
+/* End of File */
diff --git a/arch/arm/mach-snapdragon/qcom_fixup_handlers.h 
b/arch/arm/mach-snapdragon/qcom_fixup_handlers.h
new file mode 100644
index 00000000000..06ad2e86a10
--- /dev/null
+++ b/arch/arm/mach-snapdragon/qcom_fixup_handlers.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * SUBSET Parts Fixup: A tool for fixing up subset parts in a system
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ */
+
+#include <linux/libfdt.h>
+
+enum fdt_fixup_type {
+       APPEND_PROP_U32 = 0,
+       APPEND_PROP_U64 = 1,
+       SET_PROP_U32 = 2,
+       SET_PROP_U64 = 3,
+       SET_PROP_STRING = 4,
+       ADD_SUBNODE = 5,
+};
+
+/**
+ * boardinfo_fixup_handler() - Board info fixup handler.
+ * @fdt_ptr: Pointer to the device tree.
+ *
+ * This function is called to fix up the device tree blob (DTB) for the board.
+ * It adds or modifies nodes, properties, and values as necessary to ensure
+ * the DTB is in a valid state for the board.
+ *
+ * Return: None
+ */
+void boardinfo_fixup_handler(struct fdt_header *fdt_ptr);
+
+/**
+ * subsetparts_fixup_handler() - This function is the entry point for the
+ * Subset Parts fixup handler.
+ * @fdt_ptr: The firmware DT node to update.
+ *
+ * It reads the SOC info from the SMEM, extracts the disabled subset parts, and
+ * exports them to the firmware DT node.
+ *
+ * Return: None
+ */
+void subsetparts_fixup_handler(struct fdt_header *fdt_ptr);
+
+/**
+ * ddrinfo_fixup_handler() - DDRInfo Fixup handler function
+ * @fdt_ptr: Pointer to the device tree
+ *
+ * This function is responsible for updating the DDR information in
+ * the device tree.
+ *
+ * Return: None
+ */
+void ddrinfo_fixup_handler(struct fdt_header *fdt_ptr);
+
+/**
+ * fixup_dt_node() - Exports a property to the firmware DT node.
+ * @fdt_ptr: The firmware DT node to update.
+ * @node_offset: The offset in the DT node where the property should be set.
+ * @property_name: The name of the property to set.
+ * @property_value: The value of the property to set.
+ * @type: Fixup type
+ * This function sets a property in the firmware DT node with the given name 
and
+ * value.
+ *
+ * Return: 0 on success, negative on failure.
+ */
+int fixup_dt_node(void *fdt_ptr, int node_offset,
+                 const char *property_name,
+                 void *property_value,
+                 enum fdt_fixup_type type);
diff --git a/arch/arm/mach-snapdragon/qcom_fixup_subsetparts.c 
b/arch/arm/mach-snapdragon/qcom_fixup_subsetparts.c
new file mode 100644
index 00000000000..6f1af977572
--- /dev/null
+++ b/arch/arm/mach-snapdragon/qcom_fixup_subsetparts.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* SUBSET Parts Fixup: A tool for fixing up subset parts in a system
+ *
+ * Copyright (c) 2017,2019, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ */
+
+#include <dm.h>
+#include <fdt_support.h>
+#include <smem.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <linux/libfdt.h>
+#include <soc/qcom/socinfo.h>
+#include "chipinfo_def.h"
+#include "qcom_fixup_handlers.h"
+#include "qcom-priv.h"
+
+static const unsigned char *const part_names[] = {
+       [CHIPINFO_PART_GPU] = "gpu",
+       [CHIPINFO_PART_VIDEO] = "video",
+       [CHIPINFO_PART_CAMERA] = "camera",
+       [CHIPINFO_PART_DISPLAY] = "display",
+       [CHIPINFO_PART_AUDIO] = "audio",
+       [CHIPINFO_PART_MODEM] = "modem",
+       [CHIPINFO_PART_WLAN] = "wlan",
+       [CHIPINFO_PART_COMP] = "compute",
+       [CHIPINFO_PART_SENSORS] = "sensors",
+       [CHIPINFO_PART_NPU] = "npu",
+       [CHIPINFO_PART_SPSS] = "spss",
+       [CHIPINFO_PART_NAV] = "nav",
+       [CHIPINFO_PART_COMPUTE_1] = "compute1",
+       [CHIPINFO_PART_DISPLAY_1] = "display1",
+       [CHIPINFO_PART_NSP] = "nsp",
+       [CHIPINFO_PART_EVA] = "eva",
+       [CHIPINFO_PART_PCIE] = "pcie",
+};
+
+static int chipinfo_get_disabled_cpus(u32 *value_ptr);
+static int read_cpu_subset_parts(u32 *value);
+static int chipinfo_get_disabled_features(u32 chip_info_type_idx,
+                                         u32 *disabled_feature_ptr);
+static int read_mm_subset_parts(u32 *value_ptr);
+static void read_and_export_parts_disabled_features(void *fdt_ptr,
+                                                   int node_offset);
+static int add_platform_info_node(void *fdt_ptr);
+
+/**
+ * chipinfo_get_disabled_cpus() - Retrieves the disabled CPUs from the SOC 
info.
+ * @value_ptr: A pointer to a u32 variable to store the disabled CPUs.
+ *
+ * This function reads the SOC info from the SMEM and extracts the disabled
+ * CPUs.
+ *
+ * Return: 0 on success, negative on failure.
+ */
+static int chipinfo_get_disabled_cpus(u32 *value_ptr)
+{
+       u32 *subset_ptr;
+       struct socinfo *soc_info_ptr;
+
+       soc_info_ptr = qcom_get_socinfo();
+       if (!soc_info_ptr)
+               return log_msg_ret("Error: Failed to get socinfo\n", -1);
+
+       if (soc_info_ptr->num_clusters == 0x0) {
+               *value_ptr = 0x0;
+       } else {
+               subset_ptr = (u32 *)(soc_info_ptr
+                            + soc_info_ptr->ncluster_array_offset);
+               *value_ptr = (u32)(subset_ptr[0]);
+       }
+
+       return 0;
+}
+
+/**
+ * read_cpu_subset_parts() - Retrieves the disabled CPUs from the SOC info.
+ * @value: A pointer to a u32 variable to store the disabled CPUs.
+ *
+ * This function reads the SOC info from the SMEM and extracts the disabled
+ * CPUs.
+ *
+ * Return: 0 on success, negative on failure.
+ */
+static int read_cpu_subset_parts(u32 *value)
+{
+       int ret;
+
+       ret = chipinfo_get_disabled_cpus(value);
+       if (ret)
+               log_err("Failed to get subset[0] CPU. %d\n", ret);
+
+       return ret;
+}
+
+/**
+ * chipinfo_get_disabled_features() - Retrieves the disabled features from the 
SOC info.
+ * @chip_info_type_idx: The index of the chip info type to retrieve the
+ * disabled features for.
+ * @disabled_feature_ptr: A pointer to a u32 variable to store the disabled 
features.
+ *
+ * This function reads the SOC info from the SMEM and extracts the disabled
+ * features.
+ *
+ * Return: CHIPINFO_SUCCESS on success, CHIPINFO_ERROR_INVALID_PARAMETER on
+ * failure.
+ */
+static int chipinfo_get_disabled_features(u32 chip_info_type_idx,
+                                         u32 *disabled_feature_ptr)
+{
+       u32 *subset_ptr;
+       struct socinfo *soc_info_ptr;
+
+       if (chip_info_type_idx >= CHIPINFO_NUM_PARTS)
+               return CHIPINFO_ERROR_INVALID_PARAMETER;
+
+       soc_info_ptr = qcom_get_socinfo();
+       if (!soc_info_ptr)
+               return log_msg_ret("Error: Failed to get socinfo\n", -1);
+
+       subset_ptr = (u32 *)(soc_info_ptr
+                    + soc_info_ptr->nsubset_parts_array_offset);
+       *disabled_feature_ptr = (u32)(subset_ptr[chip_info_type_idx]);
+
+       return CHIPINFO_SUCCESS;
+}
+
+/**
+ * read_mm_subset_parts() - Retrieves the disabled MM subset parts from the 
SOC info.
+ * @value_ptr: A pointer to a u32 variable to store the disabled MM
+ * subset parts.
+ *
+ * This function reads the SOC info from the SMEM and extracts the disabled MM
+ * subset parts.
+ *
+ * Return: 0 on success, negative on failure.
+ */
+static int read_mm_subset_parts(u32 *value_ptr)
+{
+       u32 idx;
+       u32 subset_val;
+       int ret;
+       *value_ptr = 0;
+
+       for (idx = 1; idx < CHIPINFO_NUM_PARTS; idx++) {
+               subset_val = 0;
+               ret = chipinfo_get_disabled_features(idx, &subset_val);
+               if (ret) {
+                       log_err("Failed to get MM subset[%d] part. %d\n",
+                               idx, ret);
+                       continue;
+               }
+               *value_ptr |= ((subset_val & 0x01) << idx);
+       }
+       return ret;
+}
+
+/**
+ * read_and_export_parts_disabled_features() - Reads and exports the disabled
+ * features for each part.
+ * @fdt_ptr: The firmware DT node to update.
+ * @node_offset: The offset in the DT node where the features should be set.
+ *
+ * This function reads the SOC info from the SMEM and extracts the disabled
+ * features for each part. It then exports these features to the firmware DT
+ * node.
+ */
+static void read_and_export_parts_disabled_features(void *fdt_ptr, int 
node_offset)
+{
+       u32 mask, n_idx = 0, n_parts = 1;
+       int offset_child;
+       char str_buffer[24];
+       int ret, part;
+
+       for (part = CHIPINFO_PART_GPU; part <= CHIPINFO_PART_PCIE; part++) {
+               mask = 0;
+               ret = chipinfo_get_disabled_features(n_idx, &mask);
+               if (ret) {
+                       log_err("Failed to get Part %s information. %d\n",
+                               part_names[part], ret);
+                       mask = UINT32_MAX;
+                       n_parts = UINT32_MAX;
+               }
+               snprintf(str_buffer, sizeof(str_buffer), "subset-%s",
+                        part_names[part]);
+               offset_child = fixup_dt_node(fdt_ptr, node_offset,
+                                            str_buffer, NULL, ADD_SUBNODE);
+               if (offset_child < 0) {
+                       log_err("Error adding %s, Error: %d\n", str_buffer,
+                               offset_child);
+                       continue;
+               }
+               ret = fixup_dt_node(fdt_ptr, offset_child, "part-info",
+                                   (void *)&mask, SET_PROP_U32);
+               if (ret)
+                       log_err("ERROR: Cannot update part-info prop\n");
+
+               ret = fixup_dt_node(fdt_ptr, offset_child, "part-count",
+                                   (void *)&n_parts, SET_PROP_U32);
+               if (ret)
+                       log_err("ERROR: Cannot update part-count prop\n");
+       }
+}
+
+/**
+ * add_platform_info_node() - Adds the platform info node to the firmware DT.
+ * @fdt_ptr: The firmware DT to update.
+ *
+ * This function creates the platform info node in the firmware DT and sets its
+ * properties.
+ *
+ * Return: The offset of the platform info node on success, negative on 
failure.
+ */
+static int add_platform_info_node(void *fdt_ptr)
+{
+       int offset;
+
+       offset = fdt_path_offset(fdt_ptr, "/firmware/qcom,platform-parts-info");
+       if (offset >= 0)
+               return offset;
+       offset = fdt_path_offset(fdt_ptr, "/firmware");
+       if (offset < 0) {
+               offset = fixup_dt_node(fdt_ptr, 0, "firmware", NULL, 
ADD_SUBNODE);
+               if (offset < 0)
+                       return log_msg_ret("Error creating firmware node\n",
+                               offset);
+       }
+       offset = fixup_dt_node(fdt_ptr, offset, "qcom,platform-parts-info", 
NULL,
+                              ADD_SUBNODE);
+       if (offset < 0)
+               log_err("Error adding qcom,platform-parts-info, Error: %d\n",
+                       offset);
+
+       return offset;
+}
+
+/**
+ * subsetparts_fixup_handler() - This function is the entry point for the
+ * Subset Parts fixup handler.
+ * @fdt_ptr: The firmware DT node to update.
+ *
+ * It reads the SOC info from the SMEM, extracts the disabled subset parts, and
+ * exports them to the firmware DT node.
+ */
+void subsetparts_fixup_handler(struct fdt_header *fdt_ptr)
+{
+       u32 subset_parts_mm_value;
+       u32 subset_parts_cpu_value;
+       int offset;
+       int ret;
+
+       offset = add_platform_info_node(fdt_ptr);
+       if (offset < 0) {
+               log_err("Failed to add qcom,platform-parts-info node in %s\n",
+                       __func__);
+               return;
+       }
+       ret = read_mm_subset_parts(&subset_parts_mm_value);
+       if (ret) {
+               log_err("No mm Subset parts found\n");
+       } else {
+               ret = fixup_dt_node(fdt_ptr, offset, "subset-parts",
+                                   (void *)&subset_parts_mm_value, 
SET_PROP_U32);
+               if (ret)
+                       log_err("ERROR: Cannot update subset-parts prop\n");
+       }
+       ret = read_cpu_subset_parts(&subset_parts_cpu_value);
+       if (ret) {
+               log_err("No Subset parts for cpu ss found\n");
+       } else {
+               ret = fixup_dt_node(fdt_ptr, offset, "subset-cores",
+                                   (void *)&subset_parts_cpu_value, 
SET_PROP_U32);
+               if (ret)
+                       log_err("ERROR: Cannot update subset-cores prop\n");
+       }
+       read_and_export_parts_disabled_features(fdt_ptr, offset);
+}
diff --git a/arch/arm/mach-snapdragon/rampart.h 
b/arch/arm/mach-snapdragon/rampart.h
new file mode 100644
index 00000000000..58b3c6ecc1c
--- /dev/null
+++ b/arch/arm/mach-snapdragon/rampart.h
@@ -0,0 +1,236 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * RAM partition table definitions
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ */
+
+#define SMEM_USABLE_RAM_PARTITION_TABLE                402
+
+#define RAM_PARTITION_H_MAJOR  03
+#define RAM_PARTITION_H_MINOR  00
+
+typedef u8 uint8;
+typedef u32 uint32;
+typedef u64 uint64;
+
+/**
+ * Total length of zero filled name string. This is not a C
+ * string, as it can occupy the total number of bytes, and if
+ * it does, it does not require a zero terminator. It cannot
+ * be manipulated with standard string handling library functions.
+ */
+#define RAM_PART_NAME_LENGTH 16
+
+/**
+ * Number of RAM partition entries which are usable by APPS.
+ */
+#define RAM_NUM_PART_ENTRIES 32
+
+/**
+ * @name: Magic numbers
+ * Used in identifying valid RAM partition table.
+ */
+#define RAM_PART_MAGIC1     0x9DA5E0A8
+#define RAM_PART_MAGIC2     0xAF9EC4E2
+
+/**
+ * Must increment this version number whenever RAM structure of
+ * RAM partition table changes.
+ */
+#define RAM_PARTITION_VERSION   0x3
+
+/**
+ * Value which indicates the partition can grow to fill the
+ * rest of RAM. Must only be used on the last partition.
+ */
+#define RAM_PARTITION_GROW  0xFFFFFFFF
+
+/**
+ * RAM partition API return types.
+ */
+enum  ram_partition_return_type {
+       RAM_PART_SUCCESS = 0,             /* Successful return from API */
+       RAM_PART_NULL_PTR_ERR,            /* Partition table/entry null pointer 
*/
+       RAM_PART_OUT_OF_BOUND_PTR_ERR,    /* Partition table pointer is not in 
SMEM */
+       RAM_PART_TABLE_EMPTY_ERR,         /* Trying to delete entry from empty 
table */
+       RAM_PART_TABLE_FULL_ERR,          /* Trying to add entry to full table 
*/
+       RAM_PART_CATEGORY_NOT_EXIST_ERR,  /* Partition doesn't belong to any 
memory category */
+       RAM_PART_OTHER_ERR,               /* Unknown error */
+       RAM_PART_RETURN_MAX_SIZE = 0x7FFFFFFF
+};
+
+/**
+ * RAM partition attributes.
+ */
+enum ram_partition_attribute_t {
+       RAM_PARTITION_DEFAULT_ATTRB = ~0,  /* No specific attribute definition 
*/
+       RAM_PARTITION_READ_ONLY = 0,       /* Read-only RAM partition */
+       RAM_PARTITION_READWRITE,           /* Read/write RAM partition */
+       RAM_PARTITION_ATTRIBUTE_MAX_SIZE = 0x7FFFFFFF
+};
+
+/**
+ * RAM partition categories.
+ */
+enum ram_partition_category_t {
+       RAM_PARTITION_DEFAULT_CATEGORY = ~0,  /* No specific category 
definition */
+       RAM_PARTITION_IRAM = 4,                   /* IRAM RAM partition */
+       RAM_PARTITION_IMEM = 5,                   /* IMEM RAM partition */
+       RAM_PARTITION_SDRAM = 14,                  /* SDRAM type without 
specific bus information**/
+       RAM_PARTITION_CATEGORY_MAX_SIZE = 0x7FFFFFFF
+};
+
+/**
+ * RAM Partition domains.
+ * @note: For shared RAM partition, domain value would be 0b11:\n
+ * RAM_PARTITION_APPS_DOMAIN | RAM_PARTITION_MODEM_DOMAIN.
+ */
+enum ram_partition_domain_t {
+       RAM_PARTITION_DEFAULT_DOMAIN = 0,  /* 0b00: No specific domain 
definition */
+       RAM_PARTITION_APPS_DOMAIN = 1,     /* 0b01: APPS RAM partition */
+       RAM_PARTITION_MODEM_DOMAIN = 2,    /* 0b10: MODEM RAM partition */
+       RAM_PARTITION_DOMAIN_MAX_SIZE = 0x7FFFFFFF
+};
+
+/**
+ * RAM Partition types.
+ * @note: The RAM_PARTITION_SYS_MEMORY type represents DDR rams that are 
attached
+ * to the current system.
+ */
+enum ram_partition_type_t {
+       RAM_PARTITION_SYS_MEMORY = 1,        /* system memory */
+       RAM_PARTITION_BOOT_REGION_MEMORY1,   /* boot loader memory 1 */
+       RAM_PARTITION_BOOT_REGION_MEMORY2,   /* boot loader memory 2, reserved 
*/
+       RAM_PARTITION_APPSBL_MEMORY,         /* apps boot loader memory */
+       RAM_PARTITION_APPS_MEMORY,           /* apps usage memory */
+       RAM_PARTITION_TOOLS_FV_MEMORY,       /* tools usage memory */
+       RAM_PARTITION_QUANTUM_FV_MEMORY,     /* quantum usage memory */
+       RAM_PARTITION_QUEST_FV_MEMORY,       /* quest usage memory */
+       RAM_PARTITION_TYPE_MAX_SIZE = 0x7FFFFFFF
+};
+
+/**
+ * @brief: Holds information for an entry in the RAM partition table.
+ */
+struct ram_partition_entry {
+       char name[RAM_PART_NAME_LENGTH];  /* Partition name, unused for now */
+       uint64 start_address;             /* Partition start address in RAM */
+       uint64 length;                    /* Partition length in RAM in Bytes */
+       uint32 partition_attribute;       /* Partition attribute */
+       uint32 partition_category;        /* Partition category */
+       uint32 partition_domain;          /* Partition domain */
+       uint32 partition_type;            /* Partition type */
+       uint32 num_partitions;            /* Number of partitions on device */
+       uint32 hw_info;                   /* hw information such as type and 
frequency */
+       uint8 highest_bank_bit;           /* Highest bit corresponding to a 
bank */
+       uint8 reserve0;                   /* Reserved for future use */
+       uint8 reserve1;                   /* Reserved for future use */
+       uint8 reserve2;                   /* Reserved for future use */
+       uint32 min_pasr_size;             /* Minimum PASR size in MB */
+       uint64 available_length;          /* Available Partition length in RAM 
in Bytes */
+};
+
+/**
+ * @brief: Defines the RAM partition table structure
+ * @note: No matter how you change the structure, do not change the placement 
of the
+ * first four elements so that future compatibility will always be guaranteed
+ * at least for the identifiers.
+ *
+ * @note: The other portion of the structure may be changed as necessary to 
accommodate
+ * new features. Be sure to increment version number if you change it.
+ */
+struct usable_ram_partition_table {
+       uint32 magic1;          /* Magic number to identify valid RAM partition 
table */
+       uint32 magic2;          /* Magic number to identify valid RAM partition 
table */
+       uint32 version;         /* Version number to track structure definition 
changes */
+       uint32 reserved1;       /* Reserved for future use */
+
+       uint32 num_partitions;  /* Number of RAM partition table entries */
+
+       uint32 reserved2;       /* Added for 8 bytes alignment of header */
+
+       /* RAM partition table entries */
+       struct ram_partition_entry ram_part_entry[RAM_NUM_PART_ENTRIES];
+};
+
+/**
+ * Version 1 structure 32 Bit
+ * @brief: Holds information for an entry in the RAM partition table.
+ */
+struct ram_partition_entry_v1 {
+       char name[RAM_PART_NAME_LENGTH];  /* Partition name, unused for now */
+       uint64 start_address;             /* Partition start address in RAM */
+       uint64 length;                    /* Partition length in RAM in Bytes */
+       uint32 partition_attribute;       /* Partition attribute */
+       uint32 partition_category;        /* Partition category */
+       uint32 partition_domain;          /* Partition domain */
+       uint32 partition_type;            /* Partition type */
+       uint32 num_partitions;            /* Number of partitions on device */
+       uint32 hw_info;                   /* hw information such as type and 
frequency */
+       uint32 reserved4;                 /* Reserved for future use */
+       uint32 reserved5;                 /* Reserved for future use */
+};
+
+/**
+ * @brief: Defines the RAM partition table structure
+ * @note: No matter how you change the structure, do not change the placement 
of the
+ * first four elements so that future compatibility will always be guaranteed
+ * at least for the identifiers.
+ *
+ * @note: The other portion of the structure may be changed as necessary to 
accommodate
+ * new features. Be sure to increment version number if you change it.
+ */
+struct usable_ram_partition_table_v1 {
+       uint32 magic1;          /* Magic number to identify valid RAM partition 
table */
+       uint32 magic2;          /* Magic number to identify valid RAM partition 
table */
+       uint32 version;         /* Version number to track structure definition 
changes */
+       uint32 reserved1;       /* Reserved for future use */
+
+       uint32 num_partitions;  /* Number of RAM partition table entries */
+
+       uint32 reserved2;       /* Added for 8 bytes alignment of header */
+
+       /* RAM partition table entries */
+       struct ram_partition_entry_v1 ram_part_entry_v1[RAM_NUM_PART_ENTRIES];
+};
+
+/**
+ * Version 0 structure 32 Bit
+ * @brief: Holds information for an entry in the RAM partition table.
+ */
+struct ram_partition_entry_v0 {
+       char name[RAM_PART_NAME_LENGTH];  /* Partition name, unused for now */
+       uint32 start_address;             /* Partition start address in RAM */
+       uint32 length;                    /* Partition length in RAM in Bytes */
+       uint32 partition_attribute;       /* Partition attribute */
+       uint32 partition_category;        /* Partition category */
+       uint32 partition_domain;          /* Partition domain */
+       uint32 partition_type;            /* Partition type */
+       uint32 num_partitions;            /* Number of partitions on device */
+       uint32 reserved3;                 /* Reserved for future use */
+       uint32 reserved4;                 /* Reserved for future use */
+       uint32 reserved5;                 /* Reserved for future use */
+};
+
+/**
+ * @brief: Defines the RAM partition table structure
+ * @note: No matter how you change the structure, do not change the placement 
of the
+ * first four elements so that future compatibility will always be guaranteed
+ * at least for the identifiers.
+ *
+ * @note: The other portion of the structure may be changed as necessary to 
accommodate
+ * new features. Be sure to increment version number if you change it.
+ */
+struct usable_ram_partition_table_v0 {
+       uint32 magic1;          /* Magic number to identify valid RAM partition 
table */
+       uint32 magic2;          /* Magic number to identify valid RAM partition 
table */
+       uint32 version;         /* Version number to track structure definition 
changes */
+       uint32 reserved1;       /* Reserved for future use */
+
+       uint32 num_partitions;  /* Number of RAM partition table entries */
+
+       /* RAM partition table entries */
+       struct ram_partition_entry_v0 ram_part_entry_v0[RAM_NUM_PART_ENTRIES];
+};
-- 
2.34.1

Reply via email to