[PATCH 00/30] dm: Implement OF_PLATDATA_INST in driver model (part E)

This series builds on the recent dtoc implementation of build-time device instantiation.
It adds the required driver model support, which is basically a few more data structures.
With this, sandbox_spl and chromebook_coral both use the new feature.
For coral TPL there is a 1.5KB code-size reduction and a 1.75KB data-size increase:
text data bss dec hex 18836 3080 12 21928 55a8 original 17229 4896 12 22137 5679 with OF_PLATDATA_INST 17277 4896 12 22185 56a9 with OF_PLATDATA_RT
The extra data size is due to the build-time devices which are now included in the image instead of being built at runtime. Also the private data for each device is allocated in the data region at present, even through much of it is just zeroes.
The reduction in code size is due to not needing to bind devices at runtime, as a well as a simplified probe() function. Coral requires that data be copied out to RAM before being updated, so that adds a small amount to size (shown in the third line).
Quite a lot of future work is possible, including reducing the size of data structures. See [1] for more ideas. But this series implements the basic feature.
To try this out on your board, define CONFIG_SPL_OF_PLATDATA_INST and see what you get.
Note: SPL tests do not yet pass with this series. The driver_rt struct is not set up so device_get_by_driver_info_idx() does not work. This means that looking up phandles will fail. This will be addressed in a v2 series, along with documentation updates and a little more information on code-size impact.
This series is available at u-boot-dm/tin-working
[1] https://lists.denx.de/pipermail/u-boot/2020-July/418433.html
Simon Glass (30): sandbox: Drop debug message in os_spl_to_uboot() linker_lists: Allow use in data structures dm: core: Add macros to access the new linker lists dm: core: Allow dropping run-time binding of devices dm: core: Adjust uclass setup with of-platdata dm: core: Set up driver model for OF_PLATDATA_INST dm: core: Skip adding uclasses with OF_PLATDATA_INST dm: Add the new dtoc-generated files to the build dm: core: Include dt-decl.h automatically dm: test: Avoid destroying uclasses with of-platdata-inst clk: sandbox: Move priv/plat data to a header file clk: fixed-rate: Export driver parts for OF_PLATDATA_INST clk: sandbox: Create a special fixed-rate driver sandbox: Create a new sandbox_noinst build test: Run sandbox_spl tests on sandbox_noinst azure/gitlab: Add tests for sandbox_noinst dm: core: Add an option to support SPL in read-only memory dm: core: Create a struct for device runtime info dm: core: Move flags to device-runtime info dm: core: Allow storing priv/plat data separately sandbox: Define a region for device priv/plat data dm: core: Use separate priv/plat data region x86: Define a region for device priv/plat data x86: apl: Fix the header order in pmc x86: apl: Tell of-platdata about a required header file x86: itss: Tidy up bind() for of-platdata-inst x86: Support a fake PCI device with of-platdata-inst x86: Don't include reset driver in SPL x86: coral: Drop ACPI properties from of-platdata x86: apl: Use read-only SPL and new of-platdata
.azure-pipelines.yml | 3 + .gitlab-ci.yml | 10 +- arch/sandbox/cpu/os.c | 1 - arch/sandbox/cpu/u-boot-spl.lds | 8 + arch/sandbox/dts/sandbox.dtsi | 2 +- arch/sandbox/include/asm/clk.h | 24 +++ arch/x86/cpu/apollolake/Kconfig | 2 + arch/x86/cpu/apollolake/pmc.c | 2 +- arch/x86/cpu/apollolake/punit.c | 1 + arch/x86/cpu/intel_common/itss.c | 5 +- arch/x86/cpu/u-boot-spl.lds | 8 + arch/x86/dts/reset.dtsi | 2 +- arch/x86/lib/tpl.c | 1 + board/sandbox/MAINTAINERS | 7 + common/spl/Kconfig | 24 +++ configs/chromebook_coral_defconfig | 1 + configs/sandbox_noinst_defconfig | 229 +++++++++++++++++++++++++++++ configs/sandbox_spl_defconfig | 1 + drivers/clk/clk_fixed_rate.c | 14 +- drivers/clk/clk_sandbox.c | 40 ++++- drivers/clk/clk_sandbox_test.c | 6 - drivers/core/device.c | 83 ++++++++--- drivers/core/root.c | 83 +++++++++-- drivers/core/uclass.c | 5 +- dts/Kconfig | 38 +++++ include/asm-generic/global_data.h | 22 +++ include/asm-generic/sections.h | 3 + include/dm/device-internal.h | 26 ++++ include/dm/device.h | 38 ++++- include/dm/root.h | 3 + include/dm/uclass-internal.h | 23 +++ include/dm/uclass.h | 20 +++ include/dm/util.h | 9 ++ include/dt-structs.h | 2 + include/linker_lists.h | 28 ++++ include/linux/clk-provider.h | 5 + scripts/Makefile.spl | 3 +- test/dm/of_platdata.c | 2 +- test/dm/test-main.c | 3 +- test/run | 4 + 40 files changed, 724 insertions(+), 67 deletions(-) create mode 100644 configs/sandbox_noinst_defconfig

This is not needed in normal operation. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/os.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 80996a91ce7..7c870004c95 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -792,7 +792,6 @@ int os_spl_to_uboot(const char *fname) { struct sandbox_state *state = state_get_current();
- printf("%s\n", __func__); /* U-Boot will delete ram buffer after read: "--rm_memory"*/ state->ram_buf_rm = true; return os_jump_to_file(fname);

At present linker lists are designed for use in code. They make use of statements within expressions ({...}), for example.
It is possible to generate a reference to a linker_list entry that can be used in data structures, where such features are not permitted. It requires that the reference first be declared as extern. In other words the existing macro needs to be split into two parts.
Add new macros to support this.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/linker_lists.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
diff --git a/include/linker_lists.h b/include/linker_lists.h index fd98ecd297c..55631f0240c 100644 --- a/include/linker_lists.h +++ b/include/linker_lists.h @@ -211,6 +211,34 @@ _ll_result; \ })
+/** + * ll_entry_decl() - Declare a linker-generated array entry reference as extern + * + * This declares a reference to a list entry so that it can be used later, + * without needing the code in ll_entry_get(). + * + * To use this, put ll_entry_decl() somewhere in your file, then use + * ll_entry_ref() later on, to reference the entry. + * + * @_type: Data type of the entry + * @_name: Name of the entry + * @_list: Name of the list in which this entry is placed + */ +#define ll_entry_decl(_type, _name, _list) \ + extern _type _u_boot_list_2_##_list##_2_##_name + +/** + * ll_entry_ref() - Get a reference to a linker-generated array entry + * + * Once ll_entry_decl() has been used to declare the reference, this macro + * allows the entry to be accessed. + * + * This is like ll_entry_get(), but without the extra code, so it is suitable + * for putting into data structures. + */ +#define ll_entry_ref(_type, _name, _list) \ + ((_type *)&_u_boot_list_2_##_list##_2_##_name) + /** * ll_start() - Point to first entry of first linker-generated array * @_type: Data type of the entry

Add macros which work with instantiated devices and uclasses, as created at build time by dtoc. Include variants that can be used in data structures.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/dm/device-internal.h | 26 ++++++++++++++++++++++++++ include/dm/device.h | 11 +++++++++++ include/dm/uclass-internal.h | 23 +++++++++++++++++++++++ include/dm/uclass.h | 20 ++++++++++++++++++++ 4 files changed, 80 insertions(+)
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 639bbd293d9..9d7256130cd 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -10,11 +10,37 @@ #ifndef _DM_DEVICE_INTERNAL_H #define _DM_DEVICE_INTERNAL_H
+#include <linker_lists.h> #include <dm/ofnode.h>
struct device_node; struct udevice;
+/* + * These are only allowed these in code generated by dtoc, because the ordering + * is important and if other instances creep in then they may mess up the + * ordering expected by dtoc. + */ + +/* Declare a bound device ready for run-time use */ +#define DM_DEVICE_INST(__name) \ + ll_entry_declare(struct udevice, __name, udevice) + +/* Declare a bound device as an extern, so it can be referenced at build time */ +#define DM_DEVICE_DECL(__name) \ + ll_entry_decl(struct udevice, __name, udevice) + +/* + * Get a pointer to a given device, for use in data structures. This requires + * that the symbol be declared with DM_DRIVER_DECL() first + */ +#define DM_DEVICE_REF(__name) \ + ll_entry_ref(struct udevice, __name, udevice) + +/* Get a pointer to a given device */ +#define DM_DEVICE_GET(__name) \ + ll_entry_get(struct udevice, __name, udevice) + /** * device_bind() - Create a device and bind it to a driver * diff --git a/include/dm/device.h b/include/dm/device.h index e08a11c4a18..00d25c16862 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -338,6 +338,17 @@ struct driver { #define DM_DRIVER_GET(__name) \ ll_entry_get(struct driver, __name, driver)
+/* Declare a driver as an extern, so it can be referenced at build time */ +#define DM_DRIVER_DECL(__name) \ + ll_entry_decl(struct driver, __name, driver) + +/* + * Get a pointer to a given driver, for use in data structures. This requires + * that the symbol be declared with DM_DRIVER_DECL() first + */ +#define DM_DRIVER_REF(__name) \ + ll_entry_ref(struct driver, __name, driver) + /** * Declare a macro to state a alias for a driver name. This macro will * produce no code but its information will be parsed by tools like diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index c5a464be7c4..fc4d8dc2b53 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -11,6 +11,29 @@
#include <dm/ofnode.h>
+/* + * These are only allowed these in code generated by dtoc, because the ordering + * is important and if other instances creep in then they may mess up the + * ordering expected by dtoc. + */ + +/* + * Declare a uclass ready for run-time use. This adds an actual struct uclass + * to a list which is found by driver model on start-up. + */ +#define DM_UCLASS_INST(__name) \ + ll_entry_declare(struct uclass, __name, uclass) + +#define DM_UCLASS_DECL(__name) \ + ll_entry_decl(struct uclass, __name, uclass) + +/* + * Declare a uclass as an extern, so it can be referenced at build time. This + * is an extern for DM_UCLASS_INST(). + */ +#define DM_UCLASS_REF(__name) \ + ll_entry_ref(struct uclass, __name, uclass) + /** * uclass_set_priv() - Set the private data for a uclass * diff --git a/include/dm/uclass.h b/include/dm/uclass.h index b5f066dbf48..472a7145c60 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -114,6 +114,26 @@ struct uclass_driver { #define UCLASS_DRIVER(__name) \ ll_entry_declare(struct uclass_driver, __name, uclass_driver)
+/* + * These two macros are related to of-platdata, and normally only used in + * code generated by dtoc + */ + +/* + * Declare a uclass driver as an extern, so it can be referenced at build time + * This is the extern equivalent of UCLASS_DRIVER(). You need to place this at + * the top level before you use DM_UCLASS_DRIVER_REF() in a file. + */ +#define DM_UCLASS_DRIVER_DECL(__name) \ + ll_entry_decl(struct uclass_driver, __name, uclass_driver) + +/* + * Get a pointer to a given uclass driver, for use in data structures. This + * requires that the symbol be declared with DM_UCLASS_DRIVER_DECL() first + */ +#define DM_UCLASS_DRIVER_REF(__name) \ + ll_entry_ref(struct uclass_driver, __name, uclass_driver) + /** * uclass_get_priv() - Get the private data for a uclass *

With OF_PLATDATA_INST devices are bound at build time. we should not allow binding of devices at runtime. Add an option to control this.
Update the driver model core so that it does not bind devices. Update device_bind() to return an error if called.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/device.c | 38 +++++++++++++++++++++----------------- dts/Kconfig | 16 ++++++++++++++++ 2 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index aeab3836ed7..cdcf5f43ad2 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -44,6 +44,9 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, bool auto_seq = true; void *ptr;
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND)) + return -ENOSYS; + if (devp) *devp = NULL; if (!name) @@ -382,26 +385,27 @@ int device_of_to_plat(struct udevice *dev) if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID) return 0;
- /* Ensure all parents have ofdata */ - if (dev->parent) { - ret = device_of_to_plat(dev->parent); + if (!CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND)) { + /* Ensure all parents have ofdata */ + if (dev->parent) { + ret = device_of_to_plat(dev->parent); + if (ret) + goto fail; + + /* + * The device might have already been probed during + * the call to device_probe() on its parent device + * (e.g. PCI bridge devices). Test the flags again + * so that we don't mess up the device. + */ + if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID) + return 0; + } + + ret = device_alloc_priv(dev); if (ret) goto fail; - - /* - * The device might have already been probed during - * the call to device_probe() on its parent device - * (e.g. PCI bridge devices). Test the flags again - * so that we don't mess up the device. - */ - if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID) - return 0; } - - ret = device_alloc_priv(dev); - if (ret) - goto fail; - drv = dev->driver; assert(drv);
diff --git a/dts/Kconfig b/dts/Kconfig index e861ea48d01..645a2d2b84d 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -371,6 +371,14 @@ config SPL_OF_PLATDATA_INST Declare devices as udevice instances so that they do not need to be bound when U-Boot starts. This can save time and code space.
+config SPL_OF_PLATDATA_NO_BIND + bool "Don't allow run-time binding of devices" + depends on SPL_OF_PLATDATA_INST + default y + help + This removes the ability to bind devices at run time, thus saving + some code space in U-Boot. + endif
config TPL_OF_PLATDATA @@ -411,6 +419,14 @@ config TPL_OF_PLATDATA_INST Declare devices as udevice instances so that they do not need to be bound when U-Boot starts. This can save time and code space.
+config TPL_OF_PLATDATA_NO_BIND + bool "Don't allow run-time binding of devices" + depends on TPL_OF_PLATDATA_INST + default y + help + This removes the ability to bind devices at run time, thus saving + some code space in U-Boot. + endif
endmenu

When OF_PLATDATA_INST is enabled we don't need to create the uclass list. Instead we just need to point to the existing list. Update the code accordingly.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/root.c | 8 ++++++-- include/dm/root.h | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/core/root.c b/drivers/core/root.c index 78de7cdf875..74f326bf6c2 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -136,8 +136,12 @@ int dm_init(bool of_live) dm_warn("Virtual root driver already exists!\n"); return -EINVAL; } - gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST; - INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST); + if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) { + gd->uclass_root = &uclass_head; + } else { + gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST; + INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST); + }
if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) { fix_drivers(); diff --git a/include/dm/root.h b/include/dm/root.h index 89afbee6196..42510b106ab 100644 --- a/include/dm/root.h +++ b/include/dm/root.h @@ -11,6 +11,9 @@
struct udevice;
+/* Head of the uclass list if CONFIG_OF_PLATDATA_INST is enabled */ +extern struct list_head uclass_head; + /** * dm_root() - Return pointer to the top of the driver tree *

With this we don't need to scan and bind drivers, not even the root device. We just need to locate the root device that was set up at build time, then set our root in global_data to point to it.
Update the code to handle this case.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/root.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/core/root.c b/drivers/core/root.c index 74f326bf6c2..bb797f12203 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -128,6 +128,13 @@ void fix_devices(void) } }
+static int dm_setup_inst(void) +{ + DM_ROOT_NON_CONST = DM_DEVICE_GET(root); + + return 0; +} + int dm_init(bool of_live) { int ret; @@ -149,14 +156,23 @@ int dm_init(bool of_live) fix_devices(); }
- ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); - if (ret) - return ret; - if (CONFIG_IS_ENABLED(OF_CONTROL)) - dev_set_ofnode(DM_ROOT_NON_CONST, ofnode_root()); - ret = device_probe(DM_ROOT_NON_CONST); - if (ret) - return ret; + if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) { + ret = dm_setup_inst(); + if (ret) { + log_debug("dm_setup_inst() failed: %d\n", ret); + return ret; + } + } else { + ret = device_bind_by_name(NULL, false, &root_info, + &DM_ROOT_NON_CONST); + if (ret) + return ret; + if (CONFIG_IS_ENABLED(OF_CONTROL)) + dev_set_ofnode(DM_ROOT_NON_CONST, ofnode_root()); + ret = device_probe(DM_ROOT_NON_CONST); + if (ret) + return ret; + }
return 0; } @@ -345,10 +361,12 @@ int dm_init_and_scan(bool pre_reloc_only) debug("dm_init() failed: %d\n", ret); return ret; } - ret = dm_scan(pre_reloc_only); - if (ret) { - log_debug("dm_scan() failed: %d\n", ret); - return ret; + if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) { + ret = dm_scan(pre_reloc_only); + if (ret) { + log_debug("dm_scan() failed: %d\n", ret); + return ret; + } }
return 0;

There is no need to ever add new uclasses since these are set up at build time. Update the code to return an error if this is attempted.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/uclass.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index cdb975d5b31..3a13b82b922 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -147,8 +147,11 @@ int uclass_get(enum uclass_id id, struct uclass **ucp)
*ucp = NULL; uc = uclass_find(id); - if (!uc) + if (!uc) { + if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) + return -ENOENT; return uclass_add(id, ucp); + } *ucp = uc;
return 0;

Now that dtoc generates some new C files, add these to the build so that the instantiated devices and uclasses can be used.
Signed-off-by: Simon Glass sjg@chromium.org ---
scripts/Makefile.spl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 6ca33abf348..b9f135dd09e 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -120,7 +120,8 @@ endif u-boot-spl-init := $(head-y) u-boot-spl-main := $(libs-y) ifdef CONFIG_$(SPL_TPL_)OF_PLATDATA -u-boot-spl-platdata := $(obj)/dts/dt-plat.o +u-boot-spl-platdata := $(obj)/dts/dt-plat.o $(obj)/dts/dt-uclass.o \ + $(obj)/dts/dt-device.o u-boot-spl-platdata_c := $(patsubst %.o,%.c,$(u-boot-spl-platdata)) endif

When dt-structs.h is used, include the dt-decl.h header as well, so that these declarations are available.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/dt-structs.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/include/dt-structs.h b/include/dt-structs.h index f0e1c9cb901..f9ccaf56a46 100644 --- a/include/dt-structs.h +++ b/include/dt-structs.h @@ -24,7 +24,9 @@ struct phandle_2_arg { uint idx; int arg[2]; }; + #include <generated/dt-structs-gen.h> +#include <generated/dt-decl.h> #endif
#endif

It is not possible to destroy the uclasses when they are created at build time. Skip this step so that SPL test can complete successfully.
Signed-off-by: Simon Glass sjg@chromium.org ---
test/dm/test-main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 69458d62c86..3ec88ed0460 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -107,7 +107,8 @@ static int dm_do_test(struct unit_test_state *uts, struct unit_test *test, gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD); state_set_skip_delays(false);
- ut_assertok(dm_test_destroy(uts)); + if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) + ut_assertok(dm_test_destroy(uts));
return 0; }

At present the structs used by this driver are not accessible outside it, so cannot be used with OF_PLATDATA_INST. Move them to a header file to fix this.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/include/asm/clk.h | 16 ++++++++++++++++ drivers/clk/clk_sandbox.c | 7 ------- drivers/clk/clk_sandbox_test.c | 6 ------ 3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h index c184c4bffcf..03c00b0694c 100644 --- a/arch/sandbox/include/asm/clk.h +++ b/arch/sandbox/include/asm/clk.h @@ -7,6 +7,9 @@ #define __SANDBOX_CLK_H
#include <common.h> +#include <clk.h> +#include <dt-structs.h> +#include <linux/clk-provider.h>
struct udevice;
@@ -45,6 +48,19 @@ enum sandbox_clk_test_id {
#define SANDBOX_CLK_TEST_NON_DEVM_COUNT SANDBOX_CLK_TEST_ID_DEVM1
+struct sandbox_clk_priv { + bool probed; + ulong rate[SANDBOX_CLK_ID_COUNT]; + bool enabled[SANDBOX_CLK_ID_COUNT]; + bool requested[SANDBOX_CLK_ID_COUNT]; +}; + +struct sandbox_clk_test { + struct clk clks[SANDBOX_CLK_TEST_NON_DEVM_COUNT]; + struct clk *clkps[SANDBOX_CLK_TEST_ID_COUNT]; + struct clk_bulk bulk; +}; + /** * sandbox_clk_query_rate - Query the current rate of a sandbox clock. * diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c index 2c6c0e239f7..a5c1c9d300c 100644 --- a/drivers/clk/clk_sandbox.c +++ b/drivers/clk/clk_sandbox.c @@ -10,13 +10,6 @@ #include <malloc.h> #include <asm/clk.h>
-struct sandbox_clk_priv { - bool probed; - ulong rate[SANDBOX_CLK_ID_COUNT]; - bool enabled[SANDBOX_CLK_ID_COUNT]; - bool requested[SANDBOX_CLK_ID_COUNT]; -}; - static ulong sandbox_clk_get_rate(struct clk *clk) { struct sandbox_clk_priv *priv = dev_get_priv(clk->dev); diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c index e9eb738684b..8bbb7e881e2 100644 --- a/drivers/clk/clk_sandbox_test.c +++ b/drivers/clk/clk_sandbox_test.c @@ -11,12 +11,6 @@ #include <dm/device_compat.h> #include <linux/err.h>
-struct sandbox_clk_test { - struct clk clks[SANDBOX_CLK_TEST_NON_DEVM_COUNT]; - struct clk *clkps[SANDBOX_CLK_TEST_ID_COUNT]; - struct clk_bulk bulk; -}; - static const char * const sandbox_clk_test_names[] = { [SANDBOX_CLK_TEST_ID_FIXED] = "fixed", [SANDBOX_CLK_TEST_ID_SPI] = "spi",

We need to allow SoCs to create their own drivers for this so that they can use their own of-platdata structs. To minimise code duplication, export the driver operations and the ofdata_to_plat() setup function.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/clk/clk_fixed_rate.c | 14 ++++++++++---- include/linux/clk-provider.h | 5 +++++ 2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index 3c5a83c523c..09f9ef26a42 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -25,18 +25,24 @@ const struct clk_ops clk_fixed_rate_ops = { .enable = dummy_enable, };
-static int clk_fixed_rate_of_to_plat(struct udevice *dev) +void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev, + struct clk_fixed_rate *plat) { - struct clk *clk = &to_clk_fixed_rate(dev)->clk; + struct clk *clk = &plat->clk; #if !CONFIG_IS_ENABLED(OF_PLATDATA) - to_clk_fixed_rate(dev)->fixed_rate = - dev_read_u32_default(dev, "clock-frequency", 0); + plat->fixed_rate = dev_read_u32_default(dev, "clock-frequency", 0); #endif /* Make fixed rate clock accessible from higher level struct clk */ /* FIXME: This is not allowed */ dev_set_uclass_priv(dev, clk); + clk->dev = dev; clk->enable_count = 0; +} + +static int clk_fixed_rate_of_to_plat(struct udevice *dev) +{ + clk_fixed_rate_ofdata_to_plat_(dev, to_clk_fixed_rate(dev));
return 0; } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 75b16353dad..fd84fbd7d53 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -136,6 +136,8 @@ struct clk_fixed_factor { unsigned int div; };
+extern const struct clk_ops clk_fixed_rate_ops; + #define to_clk_fixed_factor(_clk) container_of(_clk, struct clk_fixed_factor,\ clk)
@@ -146,6 +148,9 @@ struct clk_fixed_rate {
#define to_clk_fixed_rate(dev) ((struct clk_fixed_rate *)dev_get_plat(dev))
+void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev, + struct clk_fixed_rate *plat); + struct clk_composite { struct clk clk; struct clk_ops ops;

Create a version of this driver for sandbox so that it can use the of-platdata struct.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/sandbox.dtsi | 2 +- arch/sandbox/include/asm/clk.h | 8 ++++++++ drivers/clk/clk_sandbox.c | 33 +++++++++++++++++++++++++++++++++ test/dm/of_platdata.c | 2 +- 4 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index d842f021760..4f35f5fef3e 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -31,7 +31,7 @@
clk_fixed: clk-fixed { u-boot,dm-pre-reloc; - compatible = "fixed-clock"; + compatible = "sandbox,fixed-clock"; #clock-cells = <0>; clock-frequency = <1234>; }; diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h index 03c00b0694c..9f26587a2f2 100644 --- a/arch/sandbox/include/asm/clk.h +++ b/arch/sandbox/include/asm/clk.h @@ -61,6 +61,14 @@ struct sandbox_clk_test { struct clk_bulk bulk; };
+/* Platform data for the sandbox fixed-rate clock driver */ +struct sandbox_clk_fixed_rate_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_sandbox_fixed_clock dtplat; +#endif + struct clk_fixed_rate fixed; +}; + /** * sandbox_clk_query_rate - Query the current rate of a sandbox clock. * diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c index a5c1c9d300c..633cc47f9d9 100644 --- a/drivers/clk/clk_sandbox.c +++ b/drivers/clk/clk_sandbox.c @@ -9,6 +9,7 @@ #include <errno.h> #include <malloc.h> #include <asm/clk.h> +#include <linux/clk-provider.h>
static ulong sandbox_clk_get_rate(struct clk *clk) { @@ -154,3 +155,35 @@ int sandbox_clk_query_requested(struct udevice *dev, int id) return -EINVAL; return priv->requested[id]; } + +int clk_fixed_rate_of_to_plat(struct udevice *dev) +{ + struct clk_fixed_rate *cplat; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct sandbox_clk_fixed_rate_plat *plat = dev_get_plat(dev); + + cplat = &plat->fixed; + cplat->fixed_rate = plat->dtplat.clock_frequency; +#else + cplat = to_clk_fixed_rate(dev); +#endif + clk_fixed_rate_ofdata_to_plat_(dev, cplat); + + return 0; +} + +static const struct udevice_id sandbox_clk_fixed_rate_match[] = { + { .compatible = "sandbox,fixed-clock" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(sandbox_fixed_clock) = { + .name = "sandbox_fixed_clock", + .id = UCLASS_CLK, + .of_match = sandbox_clk_fixed_rate_match, + .of_to_plat = clk_fixed_rate_of_to_plat, + .plat_auto = sizeof(struct sandbox_clk_fixed_rate_plat), + .ops = &clk_fixed_rate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c index cfc43a5b038..73d3d1e747b 100644 --- a/test/dm/of_platdata.c +++ b/test/dm/of_platdata.c @@ -184,7 +184,7 @@ static int dm_test_of_plat_phandle(struct unit_test_state *uts) plat = dev_get_plat(dev);
ut_assertok(device_get_by_driver_info_idx(plat->clocks[0].idx, &clk)); - ut_asserteq_str("fixed_clock", clk->name); + ut_asserteq_str("sandbox_fixed_clock", clk->name);
ut_assertok(device_get_by_driver_info_idx(plat->clocks[1].idx, &clk)); ut_asserteq_str("sandbox_clk", clk->name);

Move sandbox_spl over to use OF_PLATDATA_INST. Create a new board to test the case when this is not enabled, since we will be keeping that code around for several months and want to avoid regressions.
Signed-off-by: Simon Glass sjg@chromium.org ---
board/sandbox/MAINTAINERS | 7 + configs/sandbox_noinst_defconfig | 229 +++++++++++++++++++++++++++++++ configs/sandbox_spl_defconfig | 1 + 3 files changed, 237 insertions(+) create mode 100644 configs/sandbox_noinst_defconfig
diff --git a/board/sandbox/MAINTAINERS b/board/sandbox/MAINTAINERS index 433be48a6f1..d32561cd1d0 100644 --- a/board/sandbox/MAINTAINERS +++ b/board/sandbox/MAINTAINERS @@ -20,6 +20,13 @@ F: board/sandbox/ F: include/configs/sandbox_spl.h F: configs/sandbox_spl_defconfig
+SANDBOX NOINST BOARD +M: Simon Glass sjg@chromium.org +S: Maintained +F: board/sandbox/ +F: include/configs/sandbox_spl.h +F: configs/sandbox_noinst_defconfig + SANDBOX FLAT TREE BOARD M: Simon Glass sjg@chromium.org S: Maintained diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig new file mode 100644 index 00000000000..d193b18f47e --- /dev/null +++ b/configs/sandbox_noinst_defconfig @@ -0,0 +1,229 @@ +CONFIG_SYS_TEXT_BASE=0 +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y +CONFIG_NR_DRAM_BANKS=1 +CONFIG_SYS_MEMTEST_START=0x00100000 +CONFIG_SYS_MEMTEST_END=0x00101000 +CONFIG_ENV_SIZE=0x2000 +CONFIG_SPL_SERIAL_SUPPORT=y +CONFIG_SPL_DRIVERS_MISC_SUPPORT=y +CONFIG_SPL=y +CONFIG_BOOTSTAGE_STASH_ADDR=0x0 +CONFIG_DEFAULT_DEVICE_TREE="sandbox" +CONFIG_SANDBOX_SPL=y +CONFIG_DEBUG_UART=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_FIT_VERBOSE=y +CONFIG_SPL_LOAD_FIT=y +# CONFIG_USE_SPL_FIT_GENERATOR is not set +CONFIG_BOOTSTAGE=y +CONFIG_BOOTSTAGE_REPORT=y +CONFIG_BOOTSTAGE_FDT=y +CONFIG_BOOTSTAGE_STASH=y +CONFIG_BOOTSTAGE_STASH_SIZE=0x4096 +CONFIG_CONSOLE_RECORD=y +CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_HANDOFF=y +CONFIG_SPL_BOARD_INIT=y +CONFIG_SPL_ENV_SUPPORT=y +CONFIG_SPL_I2C_SUPPORT=y +CONFIG_SPL_RTC_SUPPORT=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_BOOTZ=y +CONFIG_CMD_BOOTEFI_HELLO=y +# CONFIG_CMD_ELF is not set +CONFIG_CMD_ASKENV=y +CONFIG_CMD_GREPENV=y +CONFIG_CMD_ERASEENV=y +CONFIG_CMD_ENV_CALLBACK=y +CONFIG_CMD_ENV_FLAGS=y +CONFIG_CMD_NVEDIT_INFO=y +CONFIG_CMD_NVEDIT_LOAD=y +CONFIG_CMD_NVEDIT_SELECT=y +CONFIG_LOOPW=y +CONFIG_CMD_MD5SUM=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_MX_CYCLIC=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_DEMO=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_GPT=y +CONFIG_CMD_IDE=y +CONFIG_CMD_I2C=y +CONFIG_CMD_OSD=y +CONFIG_CMD_PCI=y +CONFIG_CMD_REMOTEPROC=y +CONFIG_CMD_SPI=y +CONFIG_CMD_USB=y +CONFIG_BOOTP_DNS2=y +CONFIG_CMD_TFTPPUT=y +CONFIG_CMD_TFTPSRV=y +CONFIG_CMD_RARP=y +CONFIG_CMD_CDP=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_BMP=y +CONFIG_CMD_EFIDEBUG=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y +CONFIG_CMD_SOUND=y +CONFIG_CMD_QFW=y +CONFIG_CMD_BOOTSTAGE=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_TPM=y +CONFIG_CMD_TPM_TEST=y +CONFIG_CMD_CBFS=y +CONFIG_CMD_CRAMFS=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_MAC_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_OF_CONTROL=y +CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_HOSTFILE=y +CONFIG_SPL_OF_PLATDATA=y +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="host" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" +CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_NETCONSOLE=y +CONFIG_IP_DEFRAG=y +CONFIG_SPL_DM=y +CONFIG_REGMAP=y +CONFIG_SPL_REGMAP=y +CONFIG_SYSCON=y +CONFIG_SPL_SYSCON=y +CONFIG_DEVRES=y +CONFIG_DEBUG_DEVRES=y +# CONFIG_SPL_SIMPLE_BUS is not set +CONFIG_ADC=y +CONFIG_ADC_SANDBOX=y +CONFIG_AXI=y +CONFIG_AXI_SANDBOX=y +CONFIG_CLK=y +CONFIG_SPL_CLK=y +CONFIG_CPU=y +CONFIG_DM_DEMO=y +CONFIG_DM_DEMO_SIMPLE=y +CONFIG_DM_DEMO_SHAPE=y +CONFIG_SPL_FIRMWARE=y +CONFIG_GPIO_HOG=y +CONFIG_PM8916_GPIO=y +CONFIG_SANDBOX_GPIO=y +CONFIG_I2C_CROS_EC_TUNNEL=y +CONFIG_I2C_CROS_EC_LDO=y +CONFIG_DM_I2C_GPIO=y +CONFIG_SYS_I2C_SANDBOX=y +CONFIG_I2C_MUX=y +CONFIG_I2C_ARB_GPIO_CHALLENGE=y +CONFIG_CROS_EC_KEYB=y +CONFIG_I8042_KEYB=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_SANDBOX_MBOX=y +CONFIG_MISC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_I2C=y +CONFIG_CROS_EC_LPC=y +CONFIG_CROS_EC_SANDBOX=y +CONFIG_CROS_EC_SPI=y +CONFIG_IRQ=y +CONFIG_P2SB=y +CONFIG_PWRSEQ=y +CONFIG_SPL_PWRSEQ=y +CONFIG_MMC_SANDBOX=y +CONFIG_SPI_FLASH_SANDBOX=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_SPI_FLASH_EON=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_SST=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_DM_ETH=y +CONFIG_NVME=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_DM_PCI_COMPAT=y +CONFIG_PCI_SANDBOX=y +CONFIG_PHY=y +CONFIG_PHY_SANDBOX=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_SANDBOX=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_ACT8846=y +CONFIG_DM_PMIC_PFUZE100=y +CONFIG_DM_PMIC_MAX77686=y +CONFIG_DM_PMIC_MC34708=y +CONFIG_PMIC_PM8916=y +CONFIG_PMIC_RK8XX=y +CONFIG_PMIC_S2MPS11=y +CONFIG_DM_PMIC_SANDBOX=y +CONFIG_PMIC_S5M8767=y +CONFIG_PMIC_TPS65090=y +CONFIG_DM_REGULATOR=y +CONFIG_REGULATOR_ACT8846=y +CONFIG_DM_REGULATOR_PFUZE100=y +CONFIG_DM_REGULATOR_MAX77686=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_REGULATOR_RK8XX=y +CONFIG_REGULATOR_S5M8767=y +CONFIG_DM_REGULATOR_SANDBOX=y +CONFIG_REGULATOR_TPS65090=y +CONFIG_DM_PWM=y +CONFIG_PWM_SANDBOX=y +CONFIG_RAM=y +CONFIG_REMOTEPROC_SANDBOX=y +CONFIG_DM_RESET=y +CONFIG_SANDBOX_RESET=y +CONFIG_DM_RTC=y +CONFIG_SPL_DM_RTC=y +CONFIG_SANDBOX_SERIAL=y +CONFIG_SOUND=y +CONFIG_SOUND_SANDBOX=y +CONFIG_SOC_DEVICE=y +CONFIG_SANDBOX_SPI=y +CONFIG_SPMI=y +CONFIG_SPMI_SANDBOX=y +CONFIG_SYSINFO=y +CONFIG_SYSINFO_SANDBOX=y +CONFIG_SYSRESET=y +CONFIG_SPL_SYSRESET=y +CONFIG_TIMER=y +CONFIG_TIMER_EARLY=y +CONFIG_SANDBOX_TIMER=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EMUL=y +CONFIG_USB_KEYBOARD=y +CONFIG_DM_VIDEO=y +CONFIG_CONSOLE_ROTATION=y +CONFIG_CONSOLE_TRUETYPE=y +CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y +CONFIG_VIDEO_SANDBOX_SDL=y +CONFIG_OSD=y +CONFIG_SANDBOX_OSD=y +CONFIG_SPLASH_SCREEN_ALIGN=y +CONFIG_VIDEO_BMP_RLE8=y +CONFIG_FS_CBFS=y +CONFIG_FS_CRAMFS=y +# CONFIG_SPL_USE_TINY_PRINTF is not set +CONFIG_CMD_DHRYSTONE=y +CONFIG_RSA_VERIFY_WITH_PKEY=y +CONFIG_TPM=y +CONFIG_LZ4=y +CONFIG_ERRNO_STR=y +CONFIG_UNIT_TEST=y +CONFIG_SPL_UNIT_TEST=y +CONFIG_UT_TIME=y +CONFIG_UT_DM=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index d193b18f47e..52f980a61eb 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -87,6 +87,7 @@ CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y CONFIG_OF_HOSTFILE=y CONFIG_SPL_OF_PLATDATA=y +CONFIG_SPL_OF_PLATDATA_INST=y CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y CONFIG_ENV_EXT4_INTERFACE="host"

Run the tests on this build too, to prevent regressions.
Signed-off-by: Simon Glass sjg@chromium.org ---
test/run | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/test/run b/test/run index 735628e7e37..869406cd8d2 100755 --- a/test/run +++ b/test/run @@ -30,6 +30,10 @@ fi run_test "sandbox_spl" ./test/py/test.py --bd sandbox_spl --build \ -k 'test_ofplatdata or test_handoff or test_spl'
+# Run the sane tests with sandbox_noinst (i.e. without OF_PLATDATA_INST) +run_test "sandbox_spl" ./test/py/test.py --bd sandbox_noinst --build \ + -k 'test_ofplatdata or test_handoff or test_spl' + if [ -z "$tools_only" ]; then # Run tests for the flat-device-tree version of sandbox. This is a special # build which does not enable CONFIG_OF_LIVE for the live device tree, so we can

Add this new board to the test plans. Travis-CI is left out, since it is being removed soon due to lack of capacity.
Signed-off-by: Simon Glass sjg@chromium.org ---
.azure-pipelines.yml | 3 +++ .gitlab-ci.yml | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 620696c22e0..824d0ff361a 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -183,6 +183,9 @@ jobs: sandbox_spl: TEST_PY_BD: "sandbox_spl" TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" + sandbox_noinst: + TEST_PY_BD: "sandbox_noinst" + TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" sandbox_flattree: TEST_PY_BD: "sandbox_flattree" evb_ast2500: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4b0680887b5..e6cab9398f0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -165,7 +165,8 @@ Run binman, buildman, dtoc, Kconfig and patman testsuites: export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox_spl; export PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt"; export PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}"; - ./tools/buildman/buildman -o ${UBOOT_TRAVIS_BUILD_DIR} -w sandbox_spl; + ./tools/buildman/buildman -o ${UBOOT_TRAVIS_BUILD_DIR} -w + --board sandbox_spl; ./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test; ./tools/buildman/buildman -t; ./tools/dtoc/dtoc -t; @@ -201,6 +202,13 @@ sandbox_spl test.py: TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" <<: *buildman_and_testpy_dfn
+sandbox_noinst_test.py: + tags: [ 'all' ] + variables: + TEST_PY_BD: "sandbox_noinst" + TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" + <<: *buildman_and_testpy_dfn + evb-ast2500 test.py: tags: [ 'all' ] variables:

Some systems (e.g. x86 APL) run SPL from read-only memory. The device instances created by dtoc are therefore not writeable. To make things work we would need to copy the devices to read/write memory.
To avoid this, add an option to use a separate runtime struct for devices, just as is done for drivers. This can be used to hold information that changes at runtime, avoiding the need for a copy.
Also add a Kconfig option for read-only SPL, which selects this feature.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/spl/Kconfig | 24 ++++++++++++++++++++++++ dts/Kconfig | 22 ++++++++++++++++++++++ 2 files changed, 46 insertions(+)
diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 6b0186763b2..760378ccff0 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -276,6 +276,19 @@ config SPL_SEPARATE_BSS location is used. Normally we put the device tree at the end of BSS but with this option enabled, it goes at _image_binary_end.
+config SPL_READ_ONLY + bool + depends on SPL_OF_PLATDATA + # Bind cannot be supported because the udevice structs are in read-only + # memory so we cannot update the linked lists. + select SPL_OF_PLATDATA_NO_BIND + select SPL_OF_PLATDATA_RT + help + Some platforms (e.g. x86 Apollo Lake) load SPL into a read-only + section of memory. This means that of-platdata must make a copy (in + writeable memory) of anything it wants to modify, such as + device-private data. + config SPL_BANNER_PRINT bool "Enable output of the SPL banner 'U-Boot SPL ...'" default y @@ -1432,6 +1445,17 @@ config TPL_STACK The address of the initial stack-pointer for the TPL stage. Usually this will be the (aligned) top-of-stack.
+config TPL_READ_ONLY + bool + depends on TPL_OF_PLATDATA + select TPL_OF_PLATDATA_NO_BIND + select TPL_OF_PLATDATA_RT + help + Some platforms (e.g. x86 Apollo Lake) load SPL into a read-only + section of memory. This means that of-platdata must make a copy (in + writeable memory) of anything it wants to modify, such as + device-private data. + config TPL_BOOTROM_SUPPORT bool "Support returning to the BOOTROM (from TPL)" help diff --git a/dts/Kconfig b/dts/Kconfig index 645a2d2b84d..a6bfa706637 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -379,6 +379,17 @@ config SPL_OF_PLATDATA_NO_BIND This removes the ability to bind devices at run time, thus saving some code space in U-Boot.
+config SPL_OF_PLATDATA_RT + bool "Use a separate struct for device runtime data" + depends on SPL_OF_PLATDATA_INST + default y + help + For systems running SPL from read-only memory it is convenient to + separate out the runtime information, so that the devices don't need + to be copied before being used. This moves the read-write parts of + struct udevice (at present just the flags) into a separate struct, + which is allocated at runtime. + endif
config TPL_OF_PLATDATA @@ -427,6 +438,17 @@ config TPL_OF_PLATDATA_NO_BIND This removes the ability to bind devices at run time, thus saving some code space in U-Boot.
+config TPL_OF_PLATDATA_RT + bool "Use a separate struct for device runtime data" + depends on TPL_OF_PLATDATA_INST + default y + help + For systems running TPL from read-only memory it is convenient to + separate out the runtime information, so that the devices don't need + to be copied before being used. This moves the read-write parts of + struct udevice (at present just the flags) into a separate struct, + which is allocated at runtime. + endif
endmenu

At present when driver model needs to change a device it simply updates the struct udevice structure. But with of-platdata-inst most of the fields are not modified at runtime. In fact, typically only the flags need to change.
For systems running SPL from read-only memory it is convenient to separate out the runtime information, so that the devices don't need to be copied before being used.
Create a new udevice_rt table, similar to the existing driver_rt. For now it just holds the flags, although they are not used in this patch.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/root.c | 12 ++++++++++++ include/asm-generic/global_data.h | 12 ++++++++++++ include/dm/device.h | 17 ++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/core/root.c b/drivers/core/root.c index bb797f12203..6966e9a7ff1 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -132,6 +132,18 @@ static int dm_setup_inst(void) { DM_ROOT_NON_CONST = DM_DEVICE_GET(root);
+ if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) { + struct udevice_rt *urt; + int n_ents; + + /* Allocate the udevice_rt table */ + n_ents = ll_entry_count(struct udevice, udevice); + urt = calloc(n_ents, sizeof(struct udevice_rt)); + if (!urt) + return log_msg_ret("urt", -ENOMEM); + gd_set_dm_udevice_rt(urt); + } + return 0; }
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index b63575919f0..67161f624ec 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -205,6 +205,10 @@ struct global_data { /** Dynamic info about the driver */ struct driver_rt *dm_driver_rt; # endif +#if CONFIG_IS_ENABLED(OF_PLATDATA_RT) + /** @dm_udevice_rt: Dynamic info about the udevice */ + struct udevice_rt *dm_udevice_rt; +# endif #endif #ifdef CONFIG_TIMER /** @@ -465,6 +469,14 @@ struct global_data { #define gd_dm_driver_rt() NULL #endif
+#if CONFIG_IS_ENABLED(OF_PLATDATA_RT) +#define gd_set_dm_udevice_rt(dyn) gd->dm_udevice_rt = dyn +#define gd_dm_udevice_rt() gd->dm_udevice_rt +#else +#define gd_set_dm_udevice_rt(dyn) +#define gd_dm_udevice_rt() NULL +#endif + #ifdef CONFIG_GENERATE_ACPI_TABLE #define gd_acpi_ctx() gd->acpi_ctx #else diff --git a/include/dm/device.h b/include/dm/device.h index 00d25c16862..ba62b5f0365 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -166,7 +166,7 @@ struct udevice { struct list_head sibling_node; u32 flags_; int seq_; -#if !CONFIG_IS_ENABLED(OF_PLATDATA) +#if !CONFIG_IS_ENABLED(OF_PLATDATA_RT) ofnode node_; #endif #ifdef CONFIG_DEVRES @@ -174,6 +174,21 @@ struct udevice { #endif };
+/** + * udevice_rt - runtime information set up by U-Boot + * + * This is only used with OF_PLATDATA_RT + * + * There is one of these for every udevice in the linker list, indexed by + * the udevice_info idx value. + * + * @flags_: Flags for this device DM_FLAG_... (do not access outside driver + * model) + */ +struct udevice_rt { + u32 flags_; +}; + /* Maximum sequence number supported */ #define DM_MAX_SEQ 999

When of-platdata-inst is active, use the flags in the new udevice_rt table, dropping them from the main struct udevice. This ensures that the latter is not updated at runtime.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/device.c | 33 +++++++++++++++++++++++++++++++++ include/dm/device.h | 10 +++++++++- 2 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index cdcf5f43ad2..2fe42888e90 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -1077,3 +1077,36 @@ int dev_enable_by_path(const char *path) return lists_bind_fdt(parent, node, NULL, false); } #endif + +#if CONFIG_IS_ENABLED(OF_PLATDATA_RT) +static struct udevice_rt *dev_get_rt(const struct udevice *dev) +{ + struct udevice *base = ll_entry_start(struct udevice, udevice); + int idx = dev - base; + + struct udevice_rt *urt = gd_dm_udevice_rt() + idx; + + return urt; +} + +u32 dev_get_flags(const struct udevice *dev) +{ + const struct udevice_rt *urt = dev_get_rt(dev); + + return urt->flags_; +} + +void dev_or_flags(const struct udevice *dev, u32 or) +{ + struct udevice_rt *urt = dev_get_rt(dev); + + urt->flags_ |= or; +} + +void dev_bic_flags(const struct udevice *dev, u32 bic) +{ + struct udevice_rt *urt = dev_get_rt(dev); + + urt->flags_ &= ~bic; +} +#endif /* OF_PLATDATA_RT */ diff --git a/include/dm/device.h b/include/dm/device.h index ba62b5f0365..b89cc89988e 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -164,11 +164,13 @@ struct udevice { struct list_head uclass_node; struct list_head child_head; struct list_head sibling_node; - u32 flags_; int seq_; #if !CONFIG_IS_ENABLED(OF_PLATDATA_RT) ofnode node_; #endif +#if !CONFIG_IS_ENABLED(OF_PLATDATA_RT) + u32 flags_; +#endif #ifdef CONFIG_DEVRES struct list_head devres_head; #endif @@ -195,6 +197,11 @@ struct udevice_rt { /* Returns the operations for a device */ #define device_get_ops(dev) (dev->driver->ops)
+#if CONFIG_IS_ENABLED(OF_PLATDATA_RT) +u32 dev_get_flags(const struct udevice *dev); +void dev_or_flags(const struct udevice *dev, u32 or); +void dev_bic_flags(const struct udevice *dev, u32 bic); +#else static inline u32 dev_get_flags(const struct udevice *dev) { return dev->flags_; @@ -209,6 +216,7 @@ static inline void dev_bic_flags(struct udevice *dev, u32 bic) { dev->flags_ &= ~bic; } +#endif /* OF_PLATDATA_RT */
/** * dev_ofnode() - get the DT node reference associated with a udevice

At present the device priv/data data allocated by dtoc is stored in the data section along with other variables. On some platforms it is better to allocate space for it separately, e.g. if SPL is running from read-only memory.
Create a new space with the same size as that allocated by dtoc, ready for use.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/root.c | 12 ++++++++++++ include/asm-generic/global_data.h | 10 ++++++++++ include/asm-generic/sections.h | 3 +++ 3 files changed, 25 insertions(+)
diff --git a/drivers/core/root.c b/drivers/core/root.c index 6966e9a7ff1..e12d7049995 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -11,6 +11,7 @@ #include <fdtdec.h> #include <log.h> #include <malloc.h> +#include <asm-generic/sections.h> #include <linux/libfdt.h> #include <dm/acpi.h> #include <dm/device.h> @@ -134,7 +135,9 @@ static int dm_setup_inst(void)
if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) { struct udevice_rt *urt; + void *base; int n_ents; + uint size;
/* Allocate the udevice_rt table */ n_ents = ll_entry_count(struct udevice, udevice); @@ -142,6 +145,15 @@ static int dm_setup_inst(void) if (!urt) return log_msg_ret("urt", -ENOMEM); gd_set_dm_udevice_rt(urt); + + /* Now allocate space for the priv/plat data, and copy it in */ + size = __priv_data_end - __priv_data_start; + + base = calloc(1, size); + if (!base) + return log_msg_ret("priv", -ENOMEM); + memcpy(base, __priv_data_start, size); + gd_set_dm_priv_base(base); }
return 0; diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 67161f624ec..f8d8a048d55 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -208,6 +208,12 @@ struct global_data { #if CONFIG_IS_ENABLED(OF_PLATDATA_RT) /** @dm_udevice_rt: Dynamic info about the udevice */ struct udevice_rt *dm_udevice_rt; + /** + * @dm_priv_base: Base address of the priv/plat region used when + * udevices and uclasses are in read-only memory. This is NULL if not + * used + */ + void *dm_priv_base; # endif #endif #ifdef CONFIG_TIMER @@ -472,9 +478,13 @@ struct global_data { #if CONFIG_IS_ENABLED(OF_PLATDATA_RT) #define gd_set_dm_udevice_rt(dyn) gd->dm_udevice_rt = dyn #define gd_dm_udevice_rt() gd->dm_udevice_rt +#define gd_set_dm_priv_base(dyn) gd->dm_priv_base = dyn +#define gd_dm_priv_base() gd->dm_priv_base #else #define gd_set_dm_udevice_rt(dyn) #define gd_dm_udevice_rt() NULL +#define gd_set_dm_priv_base(dyn) +#define gd_dm_priv_base() NULL #endif
#ifdef CONFIG_GENERATE_ACPI_TABLE diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 0577238d60b..267f1db73f2 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -28,6 +28,9 @@ extern char __efi_helloworld_end[]; extern char __efi_var_file_begin[]; extern char __efi_var_file_end[];
+/* Private data used by of-platdata devices/uclasses */ +extern char __priv_data_start[], __priv_data_end[]; + /* Start and end of .ctors section - used for constructor calls. */ extern char __ctors_start[], __ctors_end[];

Collect this together in one place, so driver model can access set it up in a new place if needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/u-boot-spl.lds | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/sandbox/cpu/u-boot-spl.lds b/arch/sandbox/cpu/u-boot-spl.lds index 649abeb5ee7..18160436a36 100644 --- a/arch/sandbox/cpu/u-boot-spl.lds +++ b/arch/sandbox/cpu/u-boot-spl.lds @@ -13,6 +13,14 @@ SECTIONS KEEP(*(SORT(.u_boot_list*))); }
+ /* Private data for devices with OF_PLATDATA_RT */ + . = ALIGN(4); + .priv_data : { + __priv_data_start = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.priv_data*))) + __priv_data_end = .; + } + __u_boot_sandbox_option_start = .; _u_boot_sandbox_getopt : { KEEP(*(.u_boot_sandbox_getopt)) } __u_boot_sandbox_option_end = .;

Make use of the new priv/plat data region if enabled. This is implemented as a simple offset from the position set up by dtoc to the new position.
So long as all access goes through dm_priv_to_rw() this is safe.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/device.c | 12 ++++++------ drivers/core/root.c | 9 +++++++++ include/dm/util.h | 9 +++++++++ 3 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 2fe42888e90..dcf8d39f156 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -533,7 +533,7 @@ void *dev_get_plat(const struct udevice *dev) return NULL; }
- return dev->plat_; + return dm_priv_to_rw(dev->plat_); }
void *dev_get_parent_plat(const struct udevice *dev) @@ -543,7 +543,7 @@ void *dev_get_parent_plat(const struct udevice *dev) return NULL; }
- return dev->parent_plat_; + return dm_priv_to_rw(dev->parent_plat_); }
void *dev_get_uclass_plat(const struct udevice *dev) @@ -553,7 +553,7 @@ void *dev_get_uclass_plat(const struct udevice *dev) return NULL; }
- return dev->uclass_plat_; + return dm_priv_to_rw(dev->uclass_plat_); }
void *dev_get_priv(const struct udevice *dev) @@ -563,7 +563,7 @@ void *dev_get_priv(const struct udevice *dev) return NULL; }
- return dev->priv_; + return dm_priv_to_rw(dev->priv_); }
void *dev_get_uclass_priv(const struct udevice *dev) @@ -573,7 +573,7 @@ void *dev_get_uclass_priv(const struct udevice *dev) return NULL; }
- return dev->uclass_priv_; + return dm_priv_to_rw(dev->uclass_priv_); }
void *dev_get_parent_priv(const struct udevice *dev) @@ -583,7 +583,7 @@ void *dev_get_parent_priv(const struct udevice *dev) return NULL; }
- return dev->parent_priv_; + return dm_priv_to_rw(dev->parent_priv_); }
static int device_get_device_tail(struct udevice *dev, int ret, diff --git a/drivers/core/root.c b/drivers/core/root.c index e12d7049995..9d9ab676681 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -341,6 +341,15 @@ __weak int dm_scan_other(bool pre_reloc_only) return 0; }
+#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY) +void *dm_priv_to_rw(void *priv) +{ + long offset = priv - (void *)__priv_data_start; + + return gd_dm_priv_base() + offset; +} +#endif + /** * dm_scan() - Scan tables to bind devices * diff --git a/include/dm/util.h b/include/dm/util.h index 01a044992f2..138893c9354 100644 --- a/include/dm/util.h +++ b/include/dm/util.h @@ -49,3 +49,12 @@ void dm_dump_driver_compat(void); void dm_dump_static_driver_info(void);
#endif + +#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY) +void *dm_priv_to_rw(void *priv); +#else +static inline void *dm_priv_to_rw(void *priv) +{ + return priv; +} +#endif

Collect this together in one place, so driver model can access set it up in a new place if needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/u-boot-spl.lds | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds index e6c22895b35..7ff037a781a 100644 --- a/arch/x86/cpu/u-boot-spl.lds +++ b/arch/x86/cpu/u-boot-spl.lds @@ -32,6 +32,14 @@ SECTIONS . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+ . = ALIGN(4); + + .priv_data : { + __priv_data_start = .; + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.priv_data*))) + __priv_data_end = .; + } + . = ALIGN(4); .data : { *(.data*) }

The dm.h header should come first. In fact it needs to, since otherwise the driver model definitions are not available to dt-structs.h
Fix this, since it causes problems with OF_PLATDATA_INST.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/apollolake/pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/cpu/apollolake/pmc.c b/arch/x86/cpu/apollolake/pmc.c index e23d38ea072..1d21187c96d 100644 --- a/arch/x86/cpu/apollolake/pmc.c +++ b/arch/x86/cpu/apollolake/pmc.c @@ -9,8 +9,8 @@ #define LOG_CATEGORY UCLASS_ACPI_PMC
#include <common.h> -#include <dt-structs.h> #include <dm.h> +#include <dt-structs.h> #include <log.h> #include <spl.h> #include <acpi/acpi_s3.h>

This enum is needed to generate build-time devices. Tell dtoc where to find the header, to avoid compile errors in the generated code.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/apollolake/punit.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/x86/cpu/apollolake/punit.c b/arch/x86/cpu/apollolake/punit.c index e67c011e22c..5ed7963579e 100644 --- a/arch/x86/cpu/apollolake/punit.c +++ b/arch/x86/cpu/apollolake/punit.c @@ -93,4 +93,5 @@ U_BOOT_DRIVER(intel_apl_punit) = { .id = UCLASS_SYSCON, .of_match = apl_syscon_ids, .probe = apl_punit_probe, + DM_HEADER(<asm/cpu.h>) /* for X86_SYSCON_PUNIT */ };

With the standard of-platdata we must fix up driver_data manually. With of-platadata-inst this is not necessary, since it is added to the device by dtoc.
Update the code to handle this.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/intel_common/itss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/x86/cpu/intel_common/itss.c b/arch/x86/cpu/intel_common/itss.c index ae4de4ca8c6..b258970e2ee 100644 --- a/arch/x86/cpu/intel_common/itss.c +++ b/arch/x86/cpu/intel_common/itss.c @@ -152,8 +152,9 @@ static int route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
static int itss_bind(struct udevice *dev) { - /* This is not set with of-platdata, so set it manually */ - if (CONFIG_IS_ENABLED(OF_PLATDATA)) + /* This is not set with basic of-platdata, so set it manually */ + if (CONFIG_IS_ENABLED(OF_PLATDATA) && + !CONFIG_IS_ENABLED(OF_PLATDATA_INST)) dev->driver_data = X86_IRQT_ITSS;
return 0;

With TPL we don't need full PCI support and it adds to code size. Instead, a simple_bus driver is good enough to be able to read and write the PCI config and do a little basic setup.
So at present there are two drivers in U-Boot called pci_x86. One is in UCLASS_PCI, used in SPL and U-Boot proper. The other is in UCLASS_SIMPLE_BUS and used only in TPL.
Add a tag to tell dtoc about this, so it knows which one to use when generating the devices and uclasses.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/tpl.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/x86/lib/tpl.c b/arch/x86/lib/tpl.c index 04ff32277fd..dd797780ee0 100644 --- a/arch/x86/lib/tpl.c +++ b/arch/x86/lib/tpl.c @@ -144,5 +144,6 @@ U_BOOT_DRIVER(pci_x86) = { .name = "pci_x86", .id = UCLASS_SIMPLE_BUS, .of_match = of_match_ptr(tpl_fake_pci_ids), + DM_PHASE(tpl) }; #endif

We don't normally need this driver in TPL/SPL, so drop it for now. It can be enabled by individual boards if needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/dts/reset.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/dts/reset.dtsi b/arch/x86/dts/reset.dtsi index 555d0dd9608..f2ba2fb5e84 100644 --- a/arch/x86/dts/reset.dtsi +++ b/arch/x86/dts/reset.dtsi @@ -1,6 +1,6 @@ / { reset: reset { compatible = "x86,reset"; - u-boot,dm-pre-reloc; + u-boot,dm-pre-proper; }; };

We don't use these in TPL or SPL, so drop them. Also drop 'ranges' since we don't have a full PCI driver.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/chromebook_coral_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/chromebook_coral_defconfig b/configs/chromebook_coral_defconfig index 05e6ce64932..334364c4bff 100644 --- a/configs/chromebook_coral_defconfig +++ b/configs/chromebook_coral_defconfig @@ -71,6 +71,7 @@ CONFIG_MAC_PARTITION=y CONFIG_ISO_PARTITION=y CONFIG_EFI_PARTITION=y # CONFIG_SPL_EFI_PARTITION is not set +CONFIG_OF_SPL_REMOVE_PROPS="clocks clock-names interrupt-parent interrupts linux-name acpi,name acpi,path u-boot,acpi-dsdt-order u-boot,acpi-ssdt-order ranges" CONFIG_ENV_OVERWRITE=y CONFIG_REGMAP=y CONFIG_SYSCON=y

With Apollo Lake, SPL is placed in read-only memory. Set this new option so that OF_PLATDATA_INST can be used.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/apollolake/Kconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/x86/cpu/apollolake/Kconfig b/arch/x86/cpu/apollolake/Kconfig index f5dbd6cbd34..63a05149df8 100644 --- a/arch/x86/cpu/apollolake/Kconfig +++ b/arch/x86/cpu/apollolake/Kconfig @@ -20,6 +20,8 @@ config INTEL_APOLLOLAKE select INTEL_GMA_SWSMISCI select ACPI_GNVS_EXTERNAL select TPL_OF_PLATDATA_PARENT + select TPL_OF_PLATDATA_INST + select TPL_READ_ONLY imply ENABLE_MRC_CACHE imply AHCI_PCI imply SCSI

Hi Simon,
On 12/31/20 1:09 AM, Simon Glass wrote:
This series builds on the recent dtoc implementation of build-time device instantiation.
It adds the required driver model support, which is basically a few more data structures.
With this, sandbox_spl and chromebook_coral both use the new feature.
For coral TPL there is a 1.5KB code-size reduction and a 1.75KB data-size increase:
text data bss dec hex
18836 3080 12 21928 55a8 original 17229 4896 12 22137 5679 with OF_PLATDATA_INST 17277 4896 12 22185 56a9 with OF_PLATDATA_RT
The extra data size is due to the build-time devices which are now included in the image instead of being built at runtime. Also the private data for each device is allocated in the data region at present, even through much of it is just zeroes.
The reduction in code size is due to not needing to bind devices at runtime, as a well as a simplified probe() function. Coral requires that data be copied out to RAM before being updated, so that adds a small amount to size (shown in the third line).
Quite a lot of future work is possible, including reducing the size of data structures. See [1] for more ideas. But this series implements the basic feature.
To try this out on your board, define CONFIG_SPL_OF_PLATDATA_INST and see what you get.
Note: SPL tests do not yet pass with this series. The driver_rt struct is not set up so device_get_by_driver_info_idx() does not work. This means that looking up phandles will fail. This will be addressed in a v2 series, along with documentation updates and a little more information on code-size impact.
This series is available at u-boot-dm/tin-working
[1] https://lists.denx.de/pipermail/u-boot/2020-July/418433.html
Thanks for this series. I have done a quick review, but I plan to do a deeper one and some testing during the following days.
Regards,
Walter
Simon Glass (30): sandbox: Drop debug message in os_spl_to_uboot() linker_lists: Allow use in data structures dm: core: Add macros to access the new linker lists dm: core: Allow dropping run-time binding of devices dm: core: Adjust uclass setup with of-platdata dm: core: Set up driver model for OF_PLATDATA_INST dm: core: Skip adding uclasses with OF_PLATDATA_INST dm: Add the new dtoc-generated files to the build dm: core: Include dt-decl.h automatically dm: test: Avoid destroying uclasses with of-platdata-inst clk: sandbox: Move priv/plat data to a header file clk: fixed-rate: Export driver parts for OF_PLATDATA_INST clk: sandbox: Create a special fixed-rate driver sandbox: Create a new sandbox_noinst build test: Run sandbox_spl tests on sandbox_noinst azure/gitlab: Add tests for sandbox_noinst dm: core: Add an option to support SPL in read-only memory dm: core: Create a struct for device runtime info dm: core: Move flags to device-runtime info dm: core: Allow storing priv/plat data separately sandbox: Define a region for device priv/plat data dm: core: Use separate priv/plat data region x86: Define a region for device priv/plat data x86: apl: Fix the header order in pmc x86: apl: Tell of-platdata about a required header file x86: itss: Tidy up bind() for of-platdata-inst x86: Support a fake PCI device with of-platdata-inst x86: Don't include reset driver in SPL x86: coral: Drop ACPI properties from of-platdata x86: apl: Use read-only SPL and new of-platdata
.azure-pipelines.yml | 3 + .gitlab-ci.yml | 10 +- arch/sandbox/cpu/os.c | 1 - arch/sandbox/cpu/u-boot-spl.lds | 8 + arch/sandbox/dts/sandbox.dtsi | 2 +- arch/sandbox/include/asm/clk.h | 24 +++ arch/x86/cpu/apollolake/Kconfig | 2 + arch/x86/cpu/apollolake/pmc.c | 2 +- arch/x86/cpu/apollolake/punit.c | 1 + arch/x86/cpu/intel_common/itss.c | 5 +- arch/x86/cpu/u-boot-spl.lds | 8 + arch/x86/dts/reset.dtsi | 2 +- arch/x86/lib/tpl.c | 1 + board/sandbox/MAINTAINERS | 7 + common/spl/Kconfig | 24 +++ configs/chromebook_coral_defconfig | 1 + configs/sandbox_noinst_defconfig | 229 +++++++++++++++++++++++++++++ configs/sandbox_spl_defconfig | 1 + drivers/clk/clk_fixed_rate.c | 14 +- drivers/clk/clk_sandbox.c | 40 ++++- drivers/clk/clk_sandbox_test.c | 6 - drivers/core/device.c | 83 ++++++++--- drivers/core/root.c | 83 +++++++++-- drivers/core/uclass.c | 5 +- dts/Kconfig | 38 +++++ include/asm-generic/global_data.h | 22 +++ include/asm-generic/sections.h | 3 + include/dm/device-internal.h | 26 ++++ include/dm/device.h | 38 ++++- include/dm/root.h | 3 + include/dm/uclass-internal.h | 23 +++ include/dm/uclass.h | 20 +++ include/dm/util.h | 9 ++ include/dt-structs.h | 2 + include/linker_lists.h | 28 ++++ include/linux/clk-provider.h | 5 + scripts/Makefile.spl | 3 +- test/dm/of_platdata.c | 2 +- test/dm/test-main.c | 3 +- test/run | 4 + 40 files changed, 724 insertions(+), 67 deletions(-) create mode 100644 configs/sandbox_noinst_defconfig
participants (2)
-
Simon Glass
-
Walter Lozano