of: Create of_root if no dtb provided by firmware
When enabling CONFIG_OF on a platform where 'of_root' is not populated by firmware, we end up without a root node. In order to apply overlays and create subnodes of the root node, we need one. Create this root node by unflattening an empty builtin dtb. If firmware provides a flattened device tree (FDT) then the FDT is unflattened via setup_arch(). Otherwise, the call to unflatten(_and_copy)?_device_tree() will create an empty root node. We make of_have_populated_dt() return true only if the DTB was loaded by firmware so that existing callers don't change behavior after this patch. The call in the of platform code is removed because it prevents overlays from creating platform devices when the empty root node is used. [sboyd@kernel.org: Update of_have_populated_dt() to treat this empty dtb as not populated. Drop setup_of() initcall] Signed-off-by: Frank Rowand <frowand.list@gmail.com> Link: https://lore.kernel.org/r/20230317053415.2254616-2-frowand.list@gmail.com Cc: Rob Herring <robh+dt@kernel.org> Signed-off-by: Stephen Boyd <sboyd@kernel.org> Link: https://lore.kernel.org/r/20240217010557.2381548-3-sboyd@kernel.org Signed-off-by: Rob Herring <robh@kernel.org>
This commit is contained in:
parent
dc1460fe1b
commit
7b937cc243
@ -14,9 +14,8 @@ if OF
|
|||||||
|
|
||||||
config OF_UNITTEST
|
config OF_UNITTEST
|
||||||
bool "Device Tree runtime unit tests"
|
bool "Device Tree runtime unit tests"
|
||||||
depends on !SPARC
|
depends on OF_EARLY_FLATTREE
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
select OF_EARLY_FLATTREE
|
|
||||||
select OF_RESOLVE
|
select OF_RESOLVE
|
||||||
help
|
help
|
||||||
This option builds in test cases for the device tree infrastructure
|
This option builds in test cases for the device tree infrastructure
|
||||||
@ -54,7 +53,7 @@ config OF_FLATTREE
|
|||||||
select CRC32
|
select CRC32
|
||||||
|
|
||||||
config OF_EARLY_FLATTREE
|
config OF_EARLY_FLATTREE
|
||||||
bool
|
def_bool OF && !(SPARC || ALPHA || HEXAGON || M68K || PARISC || S390)
|
||||||
select DMA_DECLARE_COHERENT if HAS_DMA && HAS_IOMEM
|
select DMA_DECLARE_COHERENT if HAS_DMA && HAS_IOMEM
|
||||||
select OF_FLATTREE
|
select OF_FLATTREE
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
obj-y = base.o cpu.o device.o module.o platform.o property.o
|
obj-y = base.o cpu.o device.o module.o platform.o property.o
|
||||||
obj-$(CONFIG_OF_KOBJ) += kobj.o
|
obj-$(CONFIG_OF_KOBJ) += kobj.o
|
||||||
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
|
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
|
||||||
obj-$(CONFIG_OF_FLATTREE) += fdt.o
|
obj-$(CONFIG_OF_FLATTREE) += fdt.o empty_root.dtb.o
|
||||||
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
|
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
|
||||||
obj-$(CONFIG_OF_PROMTREE) += pdt.o
|
obj-$(CONFIG_OF_PROMTREE) += pdt.o
|
||||||
obj-$(CONFIG_OF_ADDRESS) += address.o
|
obj-$(CONFIG_OF_ADDRESS) += address.o
|
||||||
|
6
drivers/of/empty_root.dts
Normal file
6
drivers/of/empty_root.dts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
/ {
|
||||||
|
|
||||||
|
};
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#define pr_fmt(fmt) "OF: fdt: " fmt
|
#define pr_fmt(fmt) "OF: fdt: " fmt
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <linux/crash_dump.h>
|
#include <linux/crash_dump.h>
|
||||||
#include <linux/crc32.h>
|
#include <linux/crc32.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@ -32,6 +33,13 @@
|
|||||||
|
|
||||||
#include "of_private.h"
|
#include "of_private.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* __dtb_empty_root_begin[] and __dtb_empty_root_end[] magically created by
|
||||||
|
* cmd_dt_S_dtb in scripts/Makefile.lib
|
||||||
|
*/
|
||||||
|
extern uint8_t __dtb_empty_root_begin[];
|
||||||
|
extern uint8_t __dtb_empty_root_end[];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* of_fdt_limit_memory - limit the number of regions in the /memory node
|
* of_fdt_limit_memory - limit the number of regions in the /memory node
|
||||||
* @limit: maximum entries
|
* @limit: maximum entries
|
||||||
@ -1343,7 +1351,29 @@ static void *__init copy_device_tree(void *fdt)
|
|||||||
*/
|
*/
|
||||||
void __init unflatten_device_tree(void)
|
void __init unflatten_device_tree(void)
|
||||||
{
|
{
|
||||||
__unflatten_device_tree(initial_boot_params, NULL, &of_root,
|
void *fdt = initial_boot_params;
|
||||||
|
|
||||||
|
/* Don't use the bootloader provided DTB if ACPI is enabled */
|
||||||
|
if (!acpi_disabled)
|
||||||
|
fdt = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Populate an empty root node when ACPI is enabled or bootloader
|
||||||
|
* doesn't provide one.
|
||||||
|
*/
|
||||||
|
if (!fdt) {
|
||||||
|
fdt = (void *) __dtb_empty_root_begin;
|
||||||
|
/* fdt_totalsize() will be used for copy size */
|
||||||
|
if (fdt_totalsize(fdt) >
|
||||||
|
__dtb_empty_root_end - __dtb_empty_root_begin) {
|
||||||
|
pr_err("invalid size in dtb_empty_root\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
of_fdt_crc32 = crc32_be(~0, fdt, fdt_totalsize(fdt));
|
||||||
|
fdt = copy_device_tree(fdt);
|
||||||
|
}
|
||||||
|
|
||||||
|
__unflatten_device_tree(fdt, NULL, &of_root,
|
||||||
early_init_dt_alloc_memory_arch, false);
|
early_init_dt_alloc_memory_arch, false);
|
||||||
|
|
||||||
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
|
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
|
||||||
|
@ -512,9 +512,6 @@ static int __init of_platform_default_populate_init(void)
|
|||||||
|
|
||||||
device_links_supplier_sync_state_pause();
|
device_links_supplier_sync_state_pause();
|
||||||
|
|
||||||
if (!of_have_populated_dt())
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_PPC)) {
|
if (IS_ENABLED(CONFIG_PPC)) {
|
||||||
struct device_node *boot_display = NULL;
|
struct device_node *boot_display = NULL;
|
||||||
struct platform_device *dev;
|
struct platform_device *dev;
|
||||||
|
@ -180,11 +180,6 @@ static inline bool is_of_node(const struct fwnode_handle *fwnode)
|
|||||||
&__of_fwnode_handle_node->fwnode : NULL; \
|
&__of_fwnode_handle_node->fwnode : NULL; \
|
||||||
})
|
})
|
||||||
|
|
||||||
static inline bool of_have_populated_dt(void)
|
|
||||||
{
|
|
||||||
return of_root != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool of_node_is_root(const struct device_node *node)
|
static inline bool of_node_is_root(const struct device_node *node)
|
||||||
{
|
{
|
||||||
return node && (node->parent == NULL);
|
return node && (node->parent == NULL);
|
||||||
@ -546,11 +541,6 @@ static inline struct device_node *of_find_node_with_property(
|
|||||||
|
|
||||||
#define of_fwnode_handle(node) NULL
|
#define of_fwnode_handle(node) NULL
|
||||||
|
|
||||||
static inline bool of_have_populated_dt(void)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct device_node *of_get_compatible_child(const struct device_node *parent,
|
static inline struct device_node *of_get_compatible_child(const struct device_node *parent,
|
||||||
const char *compatible)
|
const char *compatible)
|
||||||
{
|
{
|
||||||
@ -1634,6 +1624,21 @@ static inline bool of_device_is_system_power_controller(const struct device_node
|
|||||||
return of_property_read_bool(np, "system-power-controller");
|
return of_property_read_bool(np, "system-power-controller");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* of_have_populated_dt() - Has DT been populated by bootloader
|
||||||
|
*
|
||||||
|
* Return: True if a DTB has been populated by the bootloader and it isn't the
|
||||||
|
* empty builtin one. False otherwise.
|
||||||
|
*/
|
||||||
|
static inline bool of_have_populated_dt(void)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
return of_property_present(of_root, "compatible");
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Overlay support
|
* Overlay support
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user