Integrate the device tree fixup handlers into ft_board_setup() to
enable runtime device tree modifications for Qualcomm Snapdragon
platforms.
This patch adds:
1. ft_board_setup() implementation
- Calls all registered fixup handlers
- Provides central point for device tree modifications
- Executes before passing DT to kernel
2. soc_specific_fixups() function
- Handles SoC-specific device tree modifications
- Currently implements QCS615 MMC node disable
- Extensible for future SoC-specific fixups
3. fixup_dt_node() utility function
- Generic device tree node manipulation helper
- Supports multiple operation types:
* APPEND_PROP_U32/U64: Append 32/64-bit properties
* SET_PROP_U32/U64/STRING: Set property values
* ADD_SUBNODE: Add new device tree nodes
- Automatically adjusts FDT size as needed
Signed-off-by: Aswin Murugan <[email protected]>
---
arch/arm/mach-snapdragon/of_fixup.c | 114 ++++++++++++++++++++++++++++
1 file changed, 114 insertions(+)
diff --git a/arch/arm/mach-snapdragon/of_fixup.c
b/arch/arm/mach-snapdragon/of_fixup.c
index eec2c0c757e..1a74db51cae 100644
--- a/arch/arm/mach-snapdragon/of_fixup.c
+++ b/arch/arm/mach-snapdragon/of_fixup.c
@@ -26,6 +26,7 @@
#include <linux/errno.h>
#include <stdlib.h>
#include <time.h>
+#include "qcom_fixup_handlers.h"
/* U-Boot only supports USB high-speed mode on Qualcomm platforms with DWC3
* USB controllers. Rather than requiring source level DT changes, we fix up
@@ -165,7 +166,120 @@ static int qcom_of_fixup_nodes(void * __maybe_unused ctx,
struct event *event)
EVENT_SPY_FULL(EVT_OF_LIVE_BUILT, qcom_of_fixup_nodes);
+/**
+ * soc_specific_fixups() - Apply SoC-specific device tree fixups
+ * @fdt: Pointer to the device tree
+ *
+ * This function applies SoC-specific fixups based on the device tree
+ * compatible string. Each SoC can have its own fixup logic.
+ */
+static void soc_specific_fixups(struct fdt_header *fdt)
+{
+ int ret;
+
+ /* QCS615-specific fixup: Disable MMC node */
+ if (fdt_node_check_compatible(fdt, 0, "qcom,qcs615") == 0) {
+ int path_offset;
+ char prop_val[] = "disabled";
+
+ path_offset = fdt_path_offset(fdt, "/soc@0/mmc@7c4000");
+ if (path_offset >= 0) {
+ ret = fixup_dt_node(fdt, path_offset, "status",
+ (void *)prop_val, SET_PROP_STRING);
+ if (ret)
+ log_err("Failed to disable MMC node for QCS615:
%d\n", ret);
+ }
+ }
+}
+
int ft_board_setup(void __maybe_unused *blob, struct bd_info __maybe_unused
*bd)
{
+ struct fdt_header *fdt = blob;
+
+ /* Apply SoC-specific fixups */
+ soc_specific_fixups(fdt);
+
+ /* Call all common fixup handlers */
+ boardinfo_fixup_handler(fdt);
+ ddrinfo_fixup_handler(fdt);
+ subsetparts_fixup_handler(fdt);
+
return 0;
}
+
+int fixup_dt_node(void *fdt_ptr, int node_offset,
+ const char *property_name,
+ void *property_value,
+ enum fdt_fixup_type type)
+{
+ int ret;
+
+ if ((!fdt_ptr || node_offset < 0) ||
+ (!property_value && type != ADD_SUBNODE))
+ return -1;
+
+ switch (type) {
+ case APPEND_PROP_U32:
+ fdt_set_totalsize(fdt_ptr,
+ (fdt_totalsize(fdt_ptr)
+ + sizeof(struct fdt_property)
+ + strlen(property_name) + 3
+ + sizeof(u32)));
+ ret = fdt_appendprop_u32(fdt_ptr, node_offset,
+ property_name,
+ *(u32 *)property_value);
+ break;
+ case APPEND_PROP_U64:
+ fdt_set_totalsize(fdt_ptr,
+ (fdt_totalsize(fdt_ptr)
+ + sizeof(struct fdt_property)
+ + strlen(property_name) + 3
+ + sizeof(u64)));
+ ret = fdt_appendprop_u64(fdt_ptr, node_offset,
+ property_name,
+ *(u64 *)property_value);
+ break;
+ case SET_PROP_U32:
+ fdt_set_totalsize(fdt_ptr,
+ (fdt_totalsize(fdt_ptr)
+ + sizeof(struct fdt_property)
+ + strlen(property_name) + 3
+ + sizeof(u32)));
+ ret = fdt_setprop_u32(fdt_ptr, node_offset,
+ property_name,
+ *(u32 *)property_value);
+ break;
+ case SET_PROP_U64:
+ fdt_set_totalsize(fdt_ptr,
+ (fdt_totalsize(fdt_ptr)
+ + sizeof(struct fdt_property)
+ + strlen(property_name) + 3
+ + sizeof(u64)));
+ ret = fdt_setprop_u64(fdt_ptr, node_offset,
+ property_name,
+ *(u64 *)property_value);
+ break;
+ case SET_PROP_STRING:
+ fdt_set_totalsize(fdt_ptr,
+ (fdt_totalsize(fdt_ptr)
+ + sizeof(struct fdt_property)
+ + strlen(property_name) + 3
+ + strlen((char *)property_value)));
+ ret = fdt_setprop_string(fdt_ptr, node_offset,
+ property_name,
+ (char *)property_value);
+ break;
+ case ADD_SUBNODE:
+ fdt_set_totalsize(fdt_ptr,
+ (fdt_totalsize(fdt_ptr)
+ + sizeof(struct fdt_property)
+ + strlen(property_name) + 3));
+ ret = fdt_add_subnode(fdt_ptr, node_offset,
+ property_name);
+ break;
+ default:
+ ret = -1;
+ }
+
+ return ret;
+}
--
2.34.1