msm: dev_tree: add support for multiple concatenated dev trees
The kernel build can suppor appending multiple device trees
after the zImage. We now iterate through the device trees
looking for a match according to
platform_id/hardware_id/soc_version in the device tree's /qcom,msm_id
node.
Change-Id: I5e6b3da7a9343af2eb1f8ac7890c06f1e2726134
Signed-off-by: Dima Zavin <dima@android.com>
Signed-off-by: Shashank Mittal <mittals@codeaurora.org>
diff --git a/platform/msm_shared/dev_tree.c b/platform/msm_shared/dev_tree.c
index ee0582d..28530b8 100644
--- a/platform/msm_shared/dev_tree.c
+++ b/platform/msm_shared/dev_tree.c
@@ -52,6 +52,66 @@
*/
extern int check_aboot_addr_range_overlap(uint32_t start, uint32_t size);
+struct msm_id
+{
+ uint32_t platform_id;
+ uint32_t hardware_id;
+ uint32_t soc_rev;
+};
+
+static bool is_dev_tree_compatible(void *dtb)
+{
+ int root_offset;
+ const void *prop;
+ char model[128];
+ struct msm_id msm_id;
+ int len;
+
+ root_offset = fdt_path_offset(dtb, "/");
+ if (root_offset < 0)
+ return false;
+
+ prop = fdt_getprop(dtb, root_offset, "model", &len);
+ if (prop && len > 0) {
+ memcpy(model, prop, MIN((int)sizeof(model), len));
+ model[sizeof(model) - 1] = '\0';
+ } else {
+ model[0] = '\0';
+ }
+
+ prop = fdt_getprop(dtb, root_offset, "qcom,msm-id", &len);
+ if (!prop || len <= 0) {
+ dprintf(INFO, "qcom,msm-id entry not found\n");
+ return false;
+ } else if (len < (int)sizeof(struct msm_id)) {
+ dprintf(INFO, "qcom,msm-id entry size mismatch (%d != %d)\n",
+ len, sizeof(struct msm_id));
+ return false;
+ }
+ msm_id.platform_id = fdt32_to_cpu(((const struct msm_id *)prop)->platform_id);
+ msm_id.hardware_id = fdt32_to_cpu(((const struct msm_id *)prop)->hardware_id);
+ msm_id.soc_rev = fdt32_to_cpu(((const struct msm_id *)prop)->soc_rev);
+
+ dprintf(INFO, "Found an appended flattened device tree (%s - %d %d 0x%x)\n",
+ *model ? model : "unknown",
+ msm_id.platform_id, msm_id.hardware_id, msm_id.soc_rev);
+
+ if (msm_id.platform_id != board_platform_id() ||
+ msm_id.hardware_id != board_hardware_id() ||
+ msm_id.soc_rev != board_soc_version()) {
+ dprintf(INFO, "Device tree's msm_id doesn't match the board: <%d %d 0x%x> != <%d %d 0x%x>\n",
+ msm_id.platform_id,
+ msm_id.hardware_id,
+ msm_id.soc_rev,
+ board_platform_id(),
+ board_hardware_id(),
+ board_soc_version());
+ return false;
+ }
+
+ return true;
+}
+
/*
* Will relocate the DTB to the tags addr if the device tree is found and return
* its address
@@ -63,46 +123,44 @@
* Return Value: DTB address : If appended device tree is found
* 'NULL' : Otherwise
*/
-void *dev_tree_appended(void *kernel, void *tags, uint32_t kernel_size)
+void *dev_tree_appended(void *kernel, uint32_t kernel_size, void *tags)
{
+ void *kernel_end = kernel + kernel_size;
uint32_t app_dtb_offset = 0;
- uint32_t size;
+ void *dtb;
memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
- /*
- * Check if we have valid offset for the DTB, if not return error.
- * If the kernel image does not have appeneded device tree, DTB offset
- * might contain some random address which is not accessible & cause
- * data abort. If kernel start + dtb offset address exceed the total
- * size of the kernel, then we dont have an appeneded DTB.
- */
- if (app_dtb_offset < kernel_size)
- {
- if (!fdt_check_header((void*) (kernel + app_dtb_offset)))
- {
- void *dtb;
- int rc;
+ dtb = kernel + app_dtb_offset;
+ while (dtb + sizeof(struct fdt_header) < kernel_end) {
+ bool compat;
+ struct fdt_header dtb_hdr;
+ uint32_t dtb_size;
- dprintf(INFO, "Found Appeneded Flattened Device tree\n");
- dtb = kernel + app_dtb_offset;
- size = fdt_totalsize(dtb);
- if (check_aboot_addr_range_overlap(tags, size))
- {
- dprintf(CRITICAL, "Appended dtb aboot overlap check failed.\n");
- return NULL;
- }
- rc = fdt_open_into(dtb, tags, size);
- if (rc == 0)
- {
- /* clear out the old DTB magic so kernel doesn't find it */
- *((uint32_t *)dtb) = 0;
- return tags;
- }
+ /* the DTB could be unaligned, so extract the header,
+ * and operate on it separately */
+ memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
+ if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
+ (dtb + fdt_totalsize((const void *)&dtb_hdr) > kernel_end))
+ break;
+ dtb_size = fdt_totalsize(&dtb_hdr);
+
+ /* now that we know we have a valid DTB, we need to copy
+ * it somewhere aligned, like tags */
+ memcpy(tags, dtb, dtb_size);
+
+ compat = is_dev_tree_compatible(tags);
+ if (compat) {
+ /* clear out the old DTB magic so kernel doesn't find it */
+ *((uint32_t *)(kernel + app_dtb_offset)) = 0;
+ return tags;
}
+
+ /* goto the next device tree if any */
+ dtb += dtb_size;
}
- else
- dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
+
+ dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
return NULL;
}
diff --git a/platform/msm_shared/include/dev_tree.h b/platform/msm_shared/include/dev_tree.h
index d0b0ca8..2a8ee01 100644
--- a/platform/msm_shared/include/dev_tree.h
+++ b/platform/msm_shared/include/dev_tree.h
@@ -70,5 +70,5 @@
int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info);
int update_device_tree(void *, const char *, void *, unsigned);
int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint32_t size, uint32_t addr);
-void *dev_tree_appended(void *kernel, void *tags, uint32_t kernel_size);
+void *dev_tree_appended(void *kernel, uint32_t kernel_size, void *tags);
#endif