From patchwork Fri Jul 14 12:55:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mario Six X-Patchwork-Id: 788470 X-Patchwork-Delegate: mario.six@gdsys.cc Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3x8CfF4bVJz9s76 for ; Fri, 14 Jul 2017 23:07:49 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 5EE9AC21FB7; Fri, 14 Jul 2017 13:04:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.7 required=5.0 tests=RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id A511CC21FC4; Fri, 14 Jul 2017 12:56:29 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 2C6BBC21FAB; Fri, 14 Jul 2017 12:56:22 +0000 (UTC) Received: from smtprelay04.ispgateway.de (smtprelay04.ispgateway.de [80.67.18.16]) by lists.denx.de (Postfix) with ESMTPS id 14817C21F5B for ; Fri, 14 Jul 2017 12:56:09 +0000 (UTC) Received: from [87.191.40.34] (helo=bob3.testumgebung.local) by smtprelay04.ispgateway.de with esmtpa (Exim 4.89) (envelope-from ) id 1dW08d-00062X-SA; Fri, 14 Jul 2017 14:56:07 +0200 From: Mario Six To: U-Boot Mailing List , Simon Glass , Dirk Eibach , Heiko Schocher , Stefan Roese , Joe Hershberger , Tom Rini Date: Fri, 14 Jul 2017 14:55:07 +0200 Message-Id: <20170714125537.14895-22-mario.six@gdsys.cc> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170714125537.14895-1-mario.six@gdsys.cc> References: <20170714125537.14895-1-mario.six@gdsys.cc> X-Df-Sender: bWFyaW8uc2l4QGdkc3lzLmNj Subject: [U-Boot] [PATCH 21/51] common: Extend board-specific DT fixup X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Commit 2a79275 ("dm: Add callback to modify the device tree") implemented a board-specific callback that can modify U-Boot's device tree before relocation to accomodate a range of hardware variations of certain boards. However, this approach only turns out to be useful when the copy of the device tree before relocation is actually writeable. If e.g. a device boots out of a NOR flash, this scheme does not work, since the modification of the flash's contents is not possible, and the unmodified device tree is relocated and used by U-Boot. To circumvent this problem, we split the modification process into two phases. In phase one we only collect information about the board by querying the hardware (reading GPIO values, probing I2C chips, etc.), and store the obtained information in a special, board-specific structure that is part of the global data structure. This phase runs prior to relocation, and utilizes the pre-relocation DM to query hardware information. In phase two, we read the information back from the structure, and do the actual manipulation of the device tree. This phase occurs *after* the relocation of the U-Boot image, but before the driver model is initialized from the device tree. Since the device tree lives in RAM alongside the U-Boot image after relocation, the tree is definitely writeable at this point. Each phase is implemented by a board-specific callback function: phase one by board_fix_fdt_get_info, which takes no arguments, and phase two by board_fix_fdt_change, which takes the writeable device tree blob as its sole argument. Since the structure where the gathered hardware information is stored is necessarily board-dependent, we create a include file where the boards utilizing the functionality can define their individually needed structures. This commit also adapts the controlcenterdc board's fixup function to the new scheme. Signed-off-by: Mario Six --- board/gdsys/a38x/controlcenterdc.c | 20 +++++- common/board_f.c | 6 +- common/board_r.c | 10 +++ doc/driver-model/fdt-fixup.txt | 129 ++++++++++++++++++++++++------------- include/asm-generic/global_data.h | 7 ++ include/common.h | 3 +- include/fdt_fixup.h | 5 ++ 7 files changed, 130 insertions(+), 50 deletions(-) create mode 100644 include/fdt_fixup.h diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c index 32168d3576..05e18bac4c 100644 --- a/board/gdsys/a38x/controlcenterdc.c +++ b/board/gdsys/a38x/controlcenterdc.c @@ -236,7 +236,7 @@ int board_late_init(void) return 0; } -int board_fix_fdt(void *rw_fdt_blob) +int board_fix_fdt_get_info(void) { struct udevice *bus = NULL; uint k; @@ -254,7 +254,23 @@ int board_fix_fdt(void *rw_fdt_blob) snprintf(name, 64, "/soc/internal-regs/i2c@11000/pca9698@%02x", k); - if (!dm_i2c_simple_probe(bus, k)) + gd->board_fixup_data.chip_exists[k - 0x21] = dm_i2c_simple_probe(bus, k); + } + + return 0; +} + +int board_fix_fdt_change(void *rw_fdt_blob) +{ + struct of_board_fixup_data data = gd->board_fixup_data; + uint k; + char name[64]; + + for (k = 0x21; k <= 0x26; k++) { + snprintf(name, 64, + "/soc/internal-regs/i2c@11000/pca9698@%02x", k); + + if (!data.chip_exists[k - 0x21]) fdt_disable_by_ofname(rw_fdt_blob, name); } diff --git a/common/board_f.c b/common/board_f.c index b258a1a73c..b835bd22bc 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -660,9 +660,9 @@ static int setup_reloc(void) } #ifdef CONFIG_OF_BOARD_FIXUP -static int fix_fdt(void) +static int fix_fdt_get_info(void) { - return board_fix_fdt((void *)gd->fdt_blob); + return board_fix_fdt_get_info(); } #endif @@ -887,7 +887,7 @@ static const init_fnc_t init_sequence_f[] = { #endif display_new_sp, #ifdef CONFIG_OF_BOARD_FIXUP - fix_fdt, + fix_fdt_get_info, #endif INIT_FUNC_WATCHDOG_RESET reloc_fdt, diff --git a/common/board_r.c b/common/board_r.c index 199cadbed1..25f27f0843 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -694,6 +694,13 @@ static int run_main_loop(void) return 0; } +#ifdef CONFIG_OF_BOARD_FIXUP +static int fix_fdt_change(void) +{ + return board_fix_fdt_change((void *)gd->fdt_blob); +} +#endif + /* * Over time we hope to remove these functions with code fragments and * stub funtcions, and instead call the relevant function directly. @@ -731,6 +738,9 @@ static init_fnc_t init_sequence_r[] = { #ifdef CONFIG_OF_LIVE initr_of_live, #endif +#ifdef CONFIG_OF_BOARD_FIXUP + fix_fdt_change, +#endif #ifdef CONFIG_DM initr_dm, #endif diff --git a/doc/driver-model/fdt-fixup.txt b/doc/driver-model/fdt-fixup.txt index 70344bd2c3..9a9467edd8 100644 --- a/doc/driver-model/fdt-fixup.txt +++ b/doc/driver-model/fdt-fixup.txt @@ -52,81 +52,122 @@ tree (at least after the relocation) would greatly simplify the solution of this problem, it is a non-negligible task to implement it, an a interim solution is needed to address the problem at least in the medium-term. -Hence, we propose a solution to this problem by offering a board-specific -call-back function, which is passed a writeable pointer to the device tree. -This function is called before the device tree is relocated, and specifically -before the main U-Boot's driver model is instantiated, hence the main U-Boot -"sees" all modifications to the device tree made in this function. Furthermore, -we have the pre-relocation driver model at our disposal at this stage, which -means that we can query the hardware for the existence and variety of the -components easily. +Hence, we propose a solution to this problem by offering a set of two board-specific +call-back functions: + + * One function which is called prior to relocation that gathers information + about the device using the pre-relocation DM instance and stores the + collected information in a special data structure within the global data + section; using the pre-relocation driver model means that we can query the + hardware for the existence and variety of the components easily. + * A second function which is called just after relocation, but before the + post-relocation DM is instantiated; it is passed a writeable pointer to the + device tree, so that it can exectute the actual modifications of the device + tree based upon the information gathered by the first function. + +Notice that since the "modification function" is called prior to the DM +instantiation, the main U-Boot "sees" all modifications to the device tree made +by the function. 2. Implementation ----------------- To take advantage of the pre-relocation device tree manipulation mechanism, -boards have to implement the function board_fix_fdt, which has the following -signature: +boards have to implement the functions board_fix_fdt_get_info and +board_fix_fdt_change, which have the following signatures: -int board_fix_fdt (void *rw_fdt_blob) +int board_fix_fdt_get_info (void) +int board_fix_fdt_change (void *rw_fdt_blob) -The passed-in void pointer is a writeable pointer to the device tree, which can -be used to manipulate the device tree using e.g. functions from -include/fdt_support.h. The return value should either be 0 in case of -successful execution of the device tree manipulation or something else for a +The void pointer passed to board_fix_fdt_change is a writeable pointer to the +device tree, which can be used to manipulate the device tree using e.g. +functions from include/fdt_support.h. The return value for both functions +should either be 0 in case of successful execution of the device information +gathering and device tree manipulation respectively or something else for a failure. Note that returning a non-null value from the function will unrecoverably halt the boot process, as with any function from init_sequence_f -(in common/board_f.c). +(in common/board_f.c) or init_sequence_r (in common/board_r.c). . -Furthermore, the Kconfig option OF_BOARD_FIXUP has to be set for the function +Furthermore, the Kconfig option OF_BOARD_FIXUP has to be set for the functions to be called: Device Tree Control -> [*] Board-specific manipulation of Device Tree -+----------------------------------------------------------+ -| WARNING: The actual manipulation of the device tree has | -| to be the _last_ set of operations in board_fix_fdt! | -| Since the pre-relocation driver model does not adapt to | -| changes made to the device tree either, its references | -| into the device tree will be invalid after manipulating | -| it, and unpredictable behavior might occur when | -| functions that rely on them are executed! | -+----------------------------------------------------------+ +The transfer of the collected device information is accomplished via the +board_fixup_data sub-structure in the global data structure. The layout of this +structure is board-defined, and every user of the mechanism should define a +suitable set of fields in include/fdt_fixup.h surrounded by preprocessor #ifdef +instructions. For example, a board with the target Kconfig variable +CONFIG_TARGET_SAMPLEBOARD that needs to check the existence of two I2C devices +and has to determine a board variant identified by an int, might add the +following member declarations for itself: -Hence, the recommended layout of the board_fixup_fdt call-back function is the -following: +#ifdef CONFIG_TARGET_SAMPLEBOARD + bool chip1_present; + bool chip2_present; + int variant; +#endif -int board_fix_fdt(void *rw_fdt_blob) +A schemetic implementation of the two functions might then look like the following: + +int board_fix_fdt_get_info(void) { /* Collect information about device's hardware and store them in e.g. - local variables */ + local variables, e.g. chip1_present, chip2_present, variant. Return a + non-zero value if the information gathering failed. */ + + /* Store the collected information in the sub-structure, so they will be + available to board_fix_fdt_change: */ - /* Do device tree manipulation using the values previously collected */ + gd->board_fixup_data.chip1_present = chip1_present; + gd->board_fixup_data.chip2_present = chip2_present; + gd->board_fixup_data.variant = variant; - /* Return 0 on successful manipulation and non-zero otherwise */ + return 0; } -If this convention is kept, both an "additive" approach, meaning that nodes for -detected components are added to the device tree, as well as a "subtractive" -approach, meaning that nodes for absent components are removed from the tree, -as well as a combination of both approaches should work. +int board_fix_fdt_change(void *rw_fdt_blob) +{ + /* Read back the information from the sub-structure: */ + + bool chip1_present = gd->board_fixup_data.chip1_present; + bool chip2_present = gd->board_fixup_data.chip2_present; + int variant = gd->board_fixup_data.variant; + + /* Employ device tree manipulation based on the information: */ + + if (chip1_present) { + ... + } + + if (chip2_present) { + ... + } + + switch(variant) + ... + } +} + +This convention of split functions also enables that both an "additive" +approach for DT manipulation, meaning that nodes for detected components are +added to the device tree, as well as a "subtractive" approach, meaning that +nodes for absent components are removed from the tree, as well as a combination +of both approaches should work. 3. Example ---------- -The controlcenterdc board (board/gdsys/a38x/controlcenterdc.c) features a -board_fix_fdt function, in which six GPIO expanders (which might be present or +The controlcenterdc board (board/gdsys/a38x/controlcenterdc.c) features +board_fix_fdt functions, in which six GPIO expanders (which might be present or not, since they are on daughter boards) on a I2C bus are queried for, and subsequently deactivated in the device tree if they are not present. -Note that the dm_i2c_simple_probe function does not use the device tree, hence -it is safe to call it after the tree has already been manipulated. - 4. Work to be done ------------------ -* The application of device tree overlay should be possible in board_fixup_fdt, - but has not been tested at this stage. +* The application of device tree overlay should be possible in + board_fixup_fdt_change, but has not been tested at this stage. -2017-01-06, Mario Six +2017-07-04, Mario Six diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index fb90be9d3e..731a4163a9 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -24,6 +24,10 @@ #include #include +#ifdef CONFIG_OF_BOARD_FIXUP +#include +#endif + typedef struct global_data { bd_t *bd; unsigned long flags; @@ -75,6 +79,9 @@ typedef struct global_data { #ifdef CONFIG_OF_LIVE struct device_node *of_root; #endif +#ifdef CONFIG_OF_BOARD_FIXUP + struct of_board_fixup_data board_fixup_data; +#endif struct jt_funcs *jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ #ifdef CONFIG_TRACE diff --git a/include/common.h b/include/common.h index 751665f8a4..80a004d4b4 100644 --- a/include/common.h +++ b/include/common.h @@ -416,7 +416,8 @@ extern ssize_t spi_write (uchar *, int, uchar *, int); /* $(BOARD)/$(BOARD).c */ int board_early_init_f (void); -int board_fix_fdt (void *rw_fdt_blob); /* manipulate the U-Boot fdt before its relocation */ +int board_fix_fdt_get_info (void); /* manipulate the U-Boot fdt before its relocation */ +int board_fix_fdt_change (void *rw_fdt_blob); /* manipulate the U-Boot fdt before its relocation */ int board_late_init (void); int board_postclk_init (void); /* after clocks/timebase, before env/serial */ int board_early_init_r (void); diff --git a/include/fdt_fixup.h b/include/fdt_fixup.h new file mode 100644 index 0000000000..9390f0a633 --- /dev/null +++ b/include/fdt_fixup.h @@ -0,0 +1,5 @@ +struct of_board_fixup_data { +#ifdef CONFIG_TARGET_CONTROLCENTERDC + bool chip_exists[6]; +#endif +};