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