]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/of/fdt.c
Merge remote-tracking branch 'dt-rh/for-next'
[karo-tx-linux.git] / drivers / of / fdt.c
index a4fa9ad31b8f7cfb62f45abf47ada0649d87b867..2fa024b97c4350c680e384c645dc17d0fc5dc177 100644 (file)
@@ -618,12 +618,72 @@ int __init of_scan_flat_dt_by_path(const char *path,
                return ret;
 }
 
+const char * __init of_flat_dt_get_machine_name(void)
+{
+       const char *name;
+       unsigned long dt_root = of_get_flat_dt_root();
+
+       name = of_get_flat_dt_prop(dt_root, "model", NULL);
+       if (!name)
+               name = of_get_flat_dt_prop(dt_root, "compatible", NULL);
+       return name;
+}
+
+/**
+ * of_flat_dt_match_machine - Iterate match tables to find matching machine.
+ *
+ * @default_match: A machine specific ptr to return in case of no match.
+ * @get_next_compat: callback function to return next compatible match table.
+ *
+ * Iterate through machine match tables to find the best match for the machine
+ * compatible string in the FDT.
+ */
+const void * __init of_flat_dt_match_machine(const void *default_match,
+               const void * (*get_next_compat)(const char * const**))
+{
+       const void *data = NULL;
+       const void *best_data = default_match;
+       const char *const *compat;
+       unsigned long dt_root;
+       unsigned int best_score = ~1, score = 0;
+
+       dt_root = of_get_flat_dt_root();
+       while ((data = get_next_compat(&compat))) {
+               score = of_flat_dt_match(dt_root, compat);
+               if (score > 0 && score < best_score) {
+                       best_data = data;
+                       best_score = score;
+               }
+       }
+       if (!best_data) {
+               const char *prop;
+               long size;
+
+               pr_err("\n unrecognized device tree list:\n[ ");
+
+               prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
+               if (prop) {
+                       while (size > 0) {
+                               printk("'%s' ", prop);
+                               size -= strlen(prop) + 1;
+                               prop += strlen(prop) + 1;
+                       }
+               }
+               printk("]\n\n");
+               return NULL;
+       }
+
+       pr_info("Machine model: %s\n", of_flat_dt_get_machine_name());
+
+       return best_data;
+}
+
 #ifdef CONFIG_BLK_DEV_INITRD
 /**
  * early_init_dt_check_for_initrd - Decode initrd location from flat tree
  * @node: reference to node containing initrd location ('chosen')
  */
-void __init early_init_dt_check_for_initrd(unsigned long node)
+static void __init early_init_dt_check_for_initrd(unsigned long node)
 {
        u64 start, end;
        unsigned long len;
@@ -641,12 +701,15 @@ void __init early_init_dt_check_for_initrd(unsigned long node)
                return;
        end = of_read_number(prop, len/4);
 
-       early_init_dt_setup_initrd_arch(start, end);
+       initrd_start = (unsigned long)__va(start);
+       initrd_end = (unsigned long)__va(end);
+       initrd_below_start_ok = 1;
+
        pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n",
                 (unsigned long long)start, (unsigned long long)end);
 }
 #else
-inline void early_init_dt_check_for_initrd(unsigned long node)
+static inline void early_init_dt_check_for_initrd(unsigned long node)
 {
 }
 #endif /* CONFIG_BLK_DEV_INITRD */
@@ -774,6 +837,25 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
 }
 
 #ifdef CONFIG_HAVE_MEMBLOCK
+void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+       const u64 phys_offset = __pa(PAGE_OFFSET);
+       base &= PAGE_MASK;
+       size &= PAGE_MASK;
+       if (base + size < phys_offset) {
+               pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
+                          base, base + size);
+               return;
+       }
+       if (base < phys_offset) {
+               pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
+                          base, phys_offset);
+               size -= phys_offset - base;
+               base = phys_offset;
+       }
+       memblock_add(base, size);
+}
+
 /*
  * called from unflatten_device_tree() to bootstrap devicetree itself
  * Architectures can override this definition if memblock isn't used
@@ -784,6 +866,32 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
 }
 #endif
 
+bool __init early_init_dt_scan(void *params)
+{
+       if (!params)
+               return false;
+
+       /* Setup flat device-tree pointer */
+       initial_boot_params = params;
+
+       /* check device tree validity */
+       if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
+               initial_boot_params = NULL;
+               return false;
+       }
+
+       /* Retrieve various information from the /chosen node */
+       of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
+
+       /* Initialize {size,address}-cells info */
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+
+       /* Setup memory, calling early_init_dt_add_memory_arch */
+       of_scan_flat_dt(early_init_dt_scan_memory, NULL);
+
+       return true;
+}
+
 /**
  * unflatten_device_tree - create tree of device_nodes from flat blob
  *
@@ -801,4 +909,28 @@ void __init unflatten_device_tree(void)
        of_alias_scan(early_init_dt_alloc_memory_arch);
 }
 
+/**
+ * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob
+ *
+ * Copies and unflattens the device-tree passed by the firmware, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used. This should only be used when the FDT memory has not been
+ * reserved such is the case when the FDT is built-in to the kernel init
+ * section. If the FDT memory is reserved already then unflatten_device_tree
+ * should be used instead.
+ */
+void __init unflatten_and_copy_device_tree(void)
+{
+       int size = __be32_to_cpu(initial_boot_params->totalsize);
+       void *dt = early_init_dt_alloc_memory_arch(size,
+               __alignof__(struct boot_param_header));
+
+       if (dt) {
+               memcpy(dt, initial_boot_params, size);
+               initial_boot_params = dt;
+       }
+       unflatten_device_tree();
+}
+
 #endif /* CONFIG_OF_EARLY_FLATTREE */