summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Simek <michal.simek@xilinx.com>2021-08-11 14:23:54 +0200
committerMichal Simek <michal.simek@xilinx.com>2021-08-26 08:14:43 +0200
commit52ff1626cf4c414c7a2423c443618017eb6e773c (patch)
treed2060f3ddb0c1ef6e94ae493f6c50649bc5f9aa7
parente69213611ea74e9c40ef0454142a1f6dc5589268 (diff)
downloadu-boot-52ff1626cf4c414c7a2423c443618017eb6e773c.tar.gz
xilinx: common: Enabling generic function for DT reselection
U-Boot support board detection at run time and based on it change DT. This feature is implemented for SOM Kria platforms which contain two eeproms which contain information about SOM module and CC (Carrier card). Full U-Boot starts with minimal DT file defined by CONFIG_DEFAULT_DEVICE_TREE which is available in multi DTB fit image. It is using default setup of board_name variable initializaed to DEVICE_TREE which corresponds to CONFIG_DEFAULT_DEVICE_TREE option. When DTB_RESELECT is enabled board_detection() is called. Keep it your mind that this code is called before relocation. board_detection() is calling xilinx_read_eeprom() which fills board_info (xilinx_board_description) structure which are parsed in board_name_decode(). Based on DT configuration and amount of nvmemX aliases name of the board is composed by concatenating CONFIG_SYS_BOARD "-" <board_name> "-rev" <board_revision> "-" <cc_name> "-rev" <cc_revision>. If CC is not present or more are available it keeps going. When board name is composed and returned from board_name_decode() it is assigned to board_name variable which is used by board_fit_config_name_match() which is called via fdtdec_setup() when it goes over config options in multi dtb FIT image. From practical point of view multi DTB image is key point here which has to contain configs for detected combinations. Unfortunately as of now they have to be full DTBs and DTBOs are not supported. That's why configuration like: config_X { description = "zynqmp-board-cc"; fdt = "board", "cc"; }; needs to be squashed together with: fdtoverlay -o zynqmp-board-cc -i arch/arm/dts/zynqmp-board.dtb \ arch/arm/dts/zynqmp-cc.dtbo and only one dtb is in fit: config_X { description = "zynqmp-board-cc"; fdt = "board-cc"; }; For creating multi DTBs fit image use mkimage -E, e.g.: mkimage -E -f all.its all.dtb When DTB_RESELECT is enabled xilinx_read_eeprom() is called before relocation and it uses calloc for getting a buffer. Because this is dynamic memory it is not relocated that's why xilinx_read_eeprom() is called again as the part of board_init(). This second read with calloc buffer placed in proper position board_late_init_xilinx() can setup u-boot variables as before. Signed-off-by: Michal Simek <michal.simek@xilinx.com>
-rw-r--r--arch/arm/dts/zynqmp-sm-k26-revA.dts3
-rw-r--r--board/xilinx/common/board.c84
2 files changed, 81 insertions, 6 deletions
diff --git a/arch/arm/dts/zynqmp-sm-k26-revA.dts b/arch/arm/dts/zynqmp-sm-k26-revA.dts
index e274100a9b..5f55df28f3 100644
--- a/arch/arm/dts/zynqmp-sm-k26-revA.dts
+++ b/arch/arm/dts/zynqmp-sm-k26-revA.dts
@@ -204,17 +204,20 @@
&i2c1 {
status = "okay";
+ u-boot,dm-pre-reloc;
clock-frequency = <400000>;
scl-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>;
sda-gpios = <&gpio 25 GPIO_ACTIVE_HIGH>;
eeprom: eeprom@50 { /* u46 - also at address 0x58 */
+ u-boot,dm-pre-reloc;
compatible = "st,24c64", "atmel,24c64"; /* st m24c64 */
reg = <0x50>;
/* WP pin EE_WP_EN connected to slg7x644092@68 */
};
eeprom_cc: eeprom@51 { /* required by spec - also at address 0x59 */
+ u-boot,dm-pre-reloc;
compatible = "st,24c64", "atmel,24c64"; /* st m24c64 */
reg = <0x51>;
};
diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c
index 9287427289..9006bd3b4d 100644
--- a/board/xilinx/common/board.c
+++ b/board/xilinx/common/board.c
@@ -19,6 +19,7 @@
#include <net.h>
#include <generated/dt.h>
#include <soc.h>
+#include <linux/ctype.h>
#include "fru.h"
@@ -188,12 +189,14 @@ static int xilinx_read_eeprom_fru(struct udevice *dev, char *name,
goto end;
}
- printf("Xilinx I2C FRU format at %s:\n", name);
fru_capture((unsigned long)fru_content);
- ret = fru_display(0);
- if (ret) {
- printf("FRU format decoding failed.\n");
- goto end;
+ if (gd->flags & GD_FLG_RELOC || (_DEBUG && CONFIG_IS_ENABLED(DTB_RESELECT))) {
+ printf("Xilinx I2C FRU format at %s:\n", name);
+ ret = fru_display(0);
+ if (ret) {
+ printf("FRU format decoding failed.\n");
+ goto end;
+ }
}
if (desc->header == EEPROM_HEADER_MAGIC) {
@@ -465,13 +468,82 @@ int print_cpuinfo(void)
#endif
#if CONFIG_IS_ENABLED(DTB_RESELECT)
+#define MAX_NAME_LENGTH 50
+
char * __maybe_unused __weak board_name_decode(void)
{
+ char *board_local_name;
+ struct xilinx_board_description *desc;
+ int i, id;
+
+ board_local_name = calloc(1, MAX_NAME_LENGTH);
+ if (!board_info)
+ return NULL;
+
+ for (id = 0; id <= highest_id; id++) {
+ desc = &board_info[id];
+
+ /* No board description */
+ if (!desc)
+ goto error;
+
+ /* Board is not detected */
+ if (desc->header != EEPROM_HEADER_MAGIC)
+ continue;
+
+ /* The first string should be soc name */
+ if (!id)
+ strcat(board_local_name, CONFIG_SYS_BOARD);
+
+ /*
+ * For two purpose here:
+ * soc_name- eg: zynqmp-
+ * and between base board and CC eg: ..revA-sck...
+ */
+ strcat(board_local_name, "-");
+
+ if (desc->name[0]) {
+ /* For DT composition name needs to be lowercase */
+ for (i = 0; i < sizeof(desc->name); i++)
+ desc->name[i] = tolower(desc->name[i]);
+
+ strcat(board_local_name, desc->name);
+ }
+ if (desc->revision[0]) {
+ strcat(board_local_name, "-rev");
+
+ /* And revision needs to be uppercase */
+ for (i = 0; i < sizeof(desc->revision); i++)
+ desc->revision[i] = toupper(desc->revision[i]);
+
+ strcat(board_local_name, desc->revision);
+ }
+ }
+
+ /*
+ * Longer strings will end up with buffer overflow and potential
+ * attacks that's why check it
+ */
+ if (strlen(board_local_name) >= MAX_NAME_LENGTH)
+ panic("Board name can't be determined\n");
+
+ if (strlen(board_local_name))
+ return board_local_name;
+
+error:
+ free(board_local_name);
return NULL;
}
bool __maybe_unused __weak board_detection(void)
{
+ if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM)) {
+ int ret;
+
+ ret = xilinx_read_eeprom();
+ return !ret ? true : false;
+ }
+
return false;
}
@@ -483,7 +555,7 @@ int embedded_dtb_select(void)
board_local_name = board_name_decode();
if (board_local_name) {
board_name = board_local_name;
- debug("Detected name: %s\n", board_name);
+ printf("Detected name: %s\n", board_name);
/* Time to change DTB on fly */
/* Both ways should work here */