aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-05-06 11:00:07 -0400
committerTom Rini <trini@konsulko.com>2021-05-06 11:00:07 -0400
commit1b8ad819cead7020d35f6251ef0cf3f393c61e51 (patch)
tree6331512066c3a921df043a1b6ba8b7c679a98230
parent8ddaf943589756442bba21e5be645cd47526d82b (diff)
parentf0b21ebd417cfe75f266b4dc16318bb3581783b9 (diff)
downloadu-boot-1b8ad819cead7020d35f6251ef0cf3f393c61e51.zip
u-boot-1b8ad819cead7020d35f6251ef0cf3f393c61e51.tar.gz
u-boot-1b8ad819cead7020d35f6251ef0cf3f393c61e51.tar.bz2
Merge branch '2021-05-06-misc-updates'
- Allow for boards to update bootargs before booting the OS (helpful in some forms of secure boot). - Enhance GPT write support. - gpio-sysinfo updates - Allow env to be appended from dtb
-rw-r--r--arch/sandbox/dts/test.dts14
-rw-r--r--cmd/gpt.c46
-rw-r--r--common/board_r.c2
-rw-r--r--common/fdt_support.c12
-rw-r--r--common/spl/spl_fit.c4
-rw-r--r--configs/sandbox64_defconfig2
-rw-r--r--configs/sandbox_defconfig2
-rw-r--r--configs/sandbox_flattree_defconfig1
-rw-r--r--configs/sandbox_noinst_defconfig1
-rw-r--r--configs/sandbox_spl_defconfig1
-rw-r--r--doc/README.gpt17
-rw-r--r--doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt37
-rw-r--r--drivers/gpio/gpio-uclass.c6
-rw-r--r--drivers/sysinfo/Kconfig8
-rw-r--r--drivers/sysinfo/Makefile1
-rw-r--r--drivers/sysinfo/gazerbeam.h8
-rw-r--r--drivers/sysinfo/gpio.c141
-rw-r--r--drivers/sysinfo/sandbox.h2
-rw-r--r--drivers/sysinfo/sysinfo-uclass.c29
-rw-r--r--env/Kconfig18
-rw-r--r--env/common.c30
-rw-r--r--include/env.h15
-rw-r--r--include/env_default.h3
-rw-r--r--include/fdt_support.h10
-rw-r--r--include/sysinfo.h26
-rw-r--r--test/dm/Makefile1
-rw-r--r--test/dm/sysinfo-gpio.c69
-rw-r--r--test/dm/sysinfo.c25
-rw-r--r--test/env/Makefile1
-rw-r--r--test/env/fdt.c20
30 files changed, 516 insertions, 36 deletions
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 4fde923..fe26ced 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -53,6 +53,13 @@
osd0 = "/osd";
};
+ config {
+ environment {
+ from_fdt = "yes";
+ fdt_env_path = "";
+ };
+ };
+
audio: audio-codec {
compatible = "sandbox,audio-codec";
#sound-dai-cells = <1>;
@@ -1526,6 +1533,13 @@
compatible = "sandbox,sysinfo-sandbox";
};
+ sysinfo-gpio {
+ compatible = "gpio-sysinfo";
+ gpios = <&gpio_a 15>, <&gpio_a 16>, <&gpio_a 17>;
+ revisions = <19>, <5>;
+ names = "rev_a", "foo";
+ };
+
some_regmapped-bus {
#address-cells = <0x1>;
#size-cells = <0x1>;
diff --git a/cmd/gpt.c b/cmd/gpt.c
index 76a95ad..17f2b83 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -350,17 +350,46 @@ static int get_gpt_info(struct blk_desc *dev_desc)
}
/* a wrapper to test get_gpt_info */
-static int do_get_gpt_info(struct blk_desc *dev_desc)
+static int do_get_gpt_info(struct blk_desc *dev_desc, char * const namestr)
{
- int ret;
+ int numparts;
+
+ numparts = get_gpt_info(dev_desc);
+
+ if (numparts > 0) {
+ if (namestr) {
+ char disk_guid[UUID_STR_LEN + 1];
+ char *partitions_list;
+ int partlistlen;
+ int ret = -1;
+
+ ret = get_disk_guid(dev_desc, disk_guid);
+ if (ret < 0)
+ return ret;
+
+ partlistlen = calc_parts_list_len(numparts);
+ partitions_list = malloc(partlistlen);
+ if (!partitions_list) {
+ del_gpt_info();
+ return -ENOMEM;
+ }
+ memset(partitions_list, '\0', partlistlen);
+
+ ret = create_gpt_partitions_list(numparts, disk_guid,
+ partitions_list);
+ if (ret < 0)
+ printf("Error: Could not create partition list string!\n");
+ else
+ env_set(namestr, partitions_list);
- ret = get_gpt_info(dev_desc);
- if (ret > 0) {
- print_gpt_info();
+ free(partitions_list);
+ } else {
+ print_gpt_info();
+ }
del_gpt_info();
return 0;
}
- return ret;
+ return numparts;
}
#endif
@@ -982,7 +1011,7 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
ret = do_disk_guid(blk_dev_desc, argv[4]);
#ifdef CONFIG_CMD_GPT_RENAME
} else if (strcmp(argv[1], "read") == 0) {
- ret = do_get_gpt_info(blk_dev_desc);
+ ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL);
} else if ((strcmp(argv[1], "swap") == 0) ||
(strcmp(argv[1], "rename") == 0)) {
ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]);
@@ -1028,8 +1057,9 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
" gpt guid mmc 0 varname\n"
#ifdef CONFIG_CMD_GPT_RENAME
"gpt partition renaming commands:\n"
- " gpt read <interface> <dev>\n"
+ " gpt read <interface> <dev> [<varname>]\n"
" - read GPT into a data structure for manipulation\n"
+ " - read GPT partitions into environment variable\n"
" gpt swap <interface> <dev> <name1> <name2>\n"
" - change all partitions named name1 to name2\n"
" and vice-versa\n"
diff --git a/common/board_r.c b/common/board_r.c
index c835ff8..3f82404 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -459,6 +459,8 @@ static int initr_env(void)
else
env_set_default(NULL, 0);
+ env_import_fdt();
+
if (IS_ENABLED(CONFIG_OF_CONTROL))
env_set_hex("fdtcontroladdr",
(unsigned long)map_to_sysmem(gd->fdt_blob));
diff --git a/common/fdt_support.c b/common/fdt_support.c
index e624bbd..7eb5ba3 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -269,6 +269,15 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end)
return 0;
}
+/**
+ * board_fdt_chosen_bootargs - boards may override this function to use
+ * alternative kernel command line arguments
+ */
+__weak char *board_fdt_chosen_bootargs(void)
+{
+ return env_get("bootargs");
+}
+
int fdt_chosen(void *fdt)
{
int nodeoffset;
@@ -286,7 +295,8 @@ int fdt_chosen(void *fdt)
if (nodeoffset < 0)
return nodeoffset;
- str = env_get("bootargs");
+ str = board_fdt_chosen_bootargs();
+
if (str) {
err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
strlen(str) + 1);
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 4288f57..caddf51 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -110,6 +110,10 @@ static int spl_fit_get_image_name(const struct spl_fit_info *ctx,
* no string in the property for this index. Check if the
* sysinfo-level code can supply one.
*/
+ rc = sysinfo_detect(sysinfo);
+ if (rc)
+ return rc;
+
rc = sysinfo_get_fit_loadable(sysinfo, index - i - 1, type,
&str);
if (rc && rc != -ENOENT)
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index 8a7e519..9a373ba 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -91,6 +91,7 @@ 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_ENV_IMPORT_FDT=y
CONFIG_BOOTP_SEND_HOSTNAME=y
CONFIG_NETCONSOLE=y
CONFIG_IP_DEFRAG=y
@@ -204,6 +205,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
+CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_TIMER=y
CONFIG_TIMER_EARLY=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 00befc8..bdbf714 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -106,6 +106,7 @@ 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_ENV_IMPORT_FDT=y
CONFIG_BOOTP_SEND_HOSTNAME=y
CONFIG_NETCONSOLE=y
CONFIG_IP_DEFRAG=y
@@ -245,6 +246,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
+CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_TIMER=y
CONFIG_TIMER_EARLY=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 97ac46d..853c944 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -178,6 +178,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
+CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_TIMER=y
CONFIG_TIMER_EARLY=y
diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig
index 2e7b138..c7fc98b 100644
--- a/configs/sandbox_noinst_defconfig
+++ b/configs/sandbox_noinst_defconfig
@@ -197,6 +197,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
+CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_TIMER=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index a713494..87223a5 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -199,6 +199,7 @@ CONFIG_SPMI=y
CONFIG_SPMI_SANDBOX=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SANDBOX=y
+CONFIG_SYSINFO_GPIO=y
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_TIMER=y
diff --git a/doc/README.gpt b/doc/README.gpt
index ac975f6..91e397d 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -237,6 +237,23 @@ doc/arch/index.rst:
=> gpt swap host 0 name othername
[ . . . ]
+Modifying GPT partition layout from U-Boot:
+===========================================
+
+The entire GPT partition layout can be exported to an environment
+variable and then modified enmasse. Users can change the partition
+numbers, offsets, names and sizes. The resulting variable can used to
+reformat the device. Here is an example of reading the GPT partitions
+into a variable and then modifying them:
+
+U-BOOT> gpt read mmc 0 current_partitions
+U-BOOT> env edit current_partitions
+edit: uuid_disk=[...];name=part1,start=0x4000,size=0x4000,uuid=[...];
+name=part2,start=0xc000,size=0xc000,uuid=[...];[ . . . ]
+
+U-BOOT> gpt write mmc 0 $current_partitions
+U-BOOT> gpt verify mmc 0 $current_partitions
+
Partition type GUID:
====================
diff --git a/doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt b/doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt
new file mode 100644
index 0000000..b5739d9
--- /dev/null
+++ b/doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt
@@ -0,0 +1,37 @@
+GPIO-based Sysinfo device
+
+This binding describes several GPIOs which specify a board revision. Each GPIO
+forms a digit in a ternary revision number. This revision is then mapped to a
+name using the revisions and names properties.
+
+Each GPIO may be floating, pulled-up, or pulled-down, mapping to digits 2, 1,
+and 0, respectively. The first GPIO forms the least-significant digit of the
+revision. For example, consider the property
+
+ gpios = <&gpio 0>, <&gpio 1>, <&gpio 2>;
+
+If GPIO 0 is pulled-up, GPIO 1 is pulled-down, and GPIO 2 is floating, then the
+revision would be
+
+ 0t201 = 2*9 + 0*3 + 1*3 = 19
+
+If instead GPIO 0 is floating, GPIO 1 is pulled-up, and GPIO 2 is pulled-down,
+then the revision would be
+
+ 0t012 = 0*9 + 1*3 + 2*1 = 5
+
+Required properties:
+- compatible: should be "gpio-sysinfo".
+- gpios: should be a list of gpios forming the revision number,
+ least-significant-digit first
+- revisions: a list of known revisions; any revisions not present will have the
+ name "unknown"
+- names: the name of each revision in revisions
+
+Example:
+sysinfo {
+ compatible = "gpio-sysinfo";
+ gpios = <&gpio_a 15>, <&gpio_a 16>, <&gpio_a 17>;
+ revisions = <19>, <5>;
+ names = "rev_a", "foo";
+};
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index e4e7f58..131099c 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -1215,9 +1215,9 @@ int gpio_get_list_count(struct udevice *dev, const char *list_name)
{
int ret;
- ret = dev_read_phandle_with_args(dev, list_name, "#gpio-cells", 0, -1,
- NULL);
- if (ret) {
+ ret = dev_count_phandle_with_args(dev, list_name, "#gpio-cells",
+ -ENOENT);
+ if (ret < 0) {
debug("%s: Node '%s', property '%s', GPIO count failed: %d\n",
__func__, dev->name, list_name, ret);
}
diff --git a/drivers/sysinfo/Kconfig b/drivers/sysinfo/Kconfig
index 85c1e81..381dcd8 100644
--- a/drivers/sysinfo/Kconfig
+++ b/drivers/sysinfo/Kconfig
@@ -30,4 +30,12 @@ config SYSINFO_SMBIOS
one which provides a way to specify this SMBIOS information in the
devicetree, without needing any board-specific functionality.
+config SYSINFO_GPIO
+ bool "Enable gpio sysinfo driver"
+ help
+ Support querying gpios to determine board revision. This uses gpios to
+ form a ternary number (when they are pulled-up, -down, or floating).
+ This ternary number is then mapped to a board revision name using
+ device tree properties.
+
endif
diff --git a/drivers/sysinfo/Makefile b/drivers/sysinfo/Makefile
index 6d04fcb..d9f708b 100644
--- a/drivers/sysinfo/Makefile
+++ b/drivers/sysinfo/Makefile
@@ -4,5 +4,6 @@
# Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
obj-y += sysinfo-uclass.o
obj-$(CONFIG_SYSINFO_GAZERBEAM) += gazerbeam.o
+obj-$(CONFIG_SYSINFO_GPIO) += gpio.o
obj-$(CONFIG_SYSINFO_SANDBOX) += sandbox.o
obj-$(CONFIG_SYSINFO_SMBIOS) += smbios.o
diff --git a/drivers/sysinfo/gazerbeam.h b/drivers/sysinfo/gazerbeam.h
index 171729d..6bf3c00 100644
--- a/drivers/sysinfo/gazerbeam.h
+++ b/drivers/sysinfo/gazerbeam.h
@@ -5,10 +5,12 @@
*
*/
+#include <sysinfo.h>
+
enum {
- BOARD_MULTICHANNEL,
- BOARD_VARIANT,
- BOARD_HWVERSION,
+ BOARD_HWVERSION = SYSINFO_ID_BOARD_MODEL,
+ BOARD_MULTICHANNEL = SYSINFO_ID_USER,
+ BOARD_VARIANT
};
enum {
diff --git a/drivers/sysinfo/gpio.c b/drivers/sysinfo/gpio.c
new file mode 100644
index 0000000..1d7f050
--- /dev/null
+++ b/drivers/sysinfo/gpio.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Sean Anderson <sean.anderson@seco.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <sysinfo.h>
+#include <asm/gpio.h>
+#include <dm/device_compat.h>
+
+/**
+ * struct sysinfo_gpio_priv - GPIO sysinfo private data
+ * @gpios: List of GPIOs used to detect the revision
+ * @gpio_num: The number of GPIOs in @gpios
+ * @revision: The revision as detected from the GPIOs.
+ */
+struct sysinfo_gpio_priv {
+ struct gpio_desc *gpios;
+ int gpio_num, revision;
+};
+
+static int sysinfo_gpio_detect(struct udevice *dev)
+{
+ int ret;
+ struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
+
+ ret = dm_gpio_get_values_as_int_base3(priv->gpios, priv->gpio_num);
+ if (ret < 0)
+ return ret;
+
+ priv->revision = ret;
+ return 0;
+}
+
+static int sysinfo_gpio_get_int(struct udevice *dev, int id, int *val)
+{
+ struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
+
+ switch (id) {
+ case SYSINFO_ID_BOARD_MODEL:
+ *val = priv->revision;
+ return 0;
+ default:
+ return -EINVAL;
+ };
+}
+
+static int sysinfo_gpio_get_str(struct udevice *dev, int id, size_t size, char *val)
+{
+ struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
+
+ switch (id) {
+ case SYSINFO_ID_BOARD_MODEL: {
+ const char *name = NULL;
+ int i, ret;
+ u32 revision;
+
+ for (i = 0; i < priv->gpio_num; i++) {
+ ret = dev_read_u32_index(dev, "revisions", i,
+ &revision);
+ if (ret) {
+ if (ret != -EOVERFLOW)
+ return ret;
+ break;
+ }
+
+ if (revision == priv->revision) {
+ ret = dev_read_string_index(dev, "names", i,
+ &name);
+ if (ret < 0)
+ return ret;
+ break;
+ }
+ }
+ if (!name)
+ name = "unknown";
+
+ strncpy(val, name, size);
+ val[size - 1] = '\0';
+ return 0;
+ } default:
+ return -EINVAL;
+ };
+}
+
+static const struct sysinfo_ops sysinfo_gpio_ops = {
+ .detect = sysinfo_gpio_detect,
+ .get_int = sysinfo_gpio_get_int,
+ .get_str = sysinfo_gpio_get_str,
+};
+
+static int sysinfo_gpio_probe(struct udevice *dev)
+{
+ int ret;
+ struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
+
+ priv->gpio_num = gpio_get_list_count(dev, "gpios");
+ if (priv->gpio_num < 0) {
+ dev_err(dev, "could not get gpios length (err = %d)\n",
+ priv->gpio_num);
+ return priv->gpio_num;
+ }
+
+ priv->gpios = calloc(priv->gpio_num, sizeof(*priv->gpios));
+ if (!priv->gpios) {
+ dev_err(dev, "could not allocate memory for %d gpios\n",
+ priv->gpio_num);
+ return -ENOMEM;
+ }
+
+ ret = gpio_request_list_by_name(dev, "gpios", priv->gpios,
+ priv->gpio_num, GPIOD_IS_IN);
+ if (ret != priv->gpio_num) {
+ dev_err(dev, "could not get gpios (err = %d)\n",
+ priv->gpio_num);
+ return ret;
+ }
+
+ if (!dev_read_bool(dev, "revisions") || !dev_read_bool(dev, "names")) {
+ dev_err(dev, "revisions or names properties missing\n");
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id sysinfo_gpio_ids[] = {
+ { .compatible = "gpio-sysinfo" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sysinfo_gpio) = {
+ .name = "sysinfo_gpio",
+ .id = UCLASS_SYSINFO,
+ .of_match = sysinfo_gpio_ids,
+ .ops = &sysinfo_gpio_ops,
+ .priv_auto = sizeof(struct sysinfo_gpio_priv),
+ .probe = sysinfo_gpio_probe,
+};
diff --git a/drivers/sysinfo/sandbox.h b/drivers/sysinfo/sandbox.h
index 2cff494..d9c5804 100644
--- a/drivers/sysinfo/sandbox.h
+++ b/drivers/sysinfo/sandbox.h
@@ -5,7 +5,7 @@
*/
enum {
- BOOL_CALLED_DETECT,
+ BOOL_CALLED_DETECT = SYSINFO_ID_USER,
INT_TEST1,
INT_TEST2,
STR_VACATIONSPOT,
diff --git a/drivers/sysinfo/sysinfo-uclass.c b/drivers/sysinfo/sysinfo-uclass.c
index 6df58fe..4a660df 100644
--- a/drivers/sysinfo/sysinfo-uclass.c
+++ b/drivers/sysinfo/sysinfo-uclass.c
@@ -8,6 +8,10 @@
#include <dm.h>
#include <sysinfo.h>
+struct sysinfo_priv {
+ bool detected;
+};
+
int sysinfo_get(struct udevice **devp)
{
return uclass_first_device_err(UCLASS_SYSINFO, devp);
@@ -15,19 +19,29 @@ int sysinfo_get(struct udevice **devp)
int sysinfo_detect(struct udevice *dev)
{
+ int ret;
+ struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
if (!ops->detect)
return -ENOSYS;
- return ops->detect(dev);
+ ret = ops->detect(dev);
+ if (!ret)
+ priv->detected = true;
+
+ return ret;
}
int sysinfo_get_fit_loadable(struct udevice *dev, int index, const char *type,
const char **strp)
{
+ struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
+ if (!priv->detected)
+ return -EPERM;
+
if (!ops->get_fit_loadable)
return -ENOSYS;
@@ -36,8 +50,12 @@ int sysinfo_get_fit_loadable(struct udevice *dev, int index, const char *type,
int sysinfo_get_bool(struct udevice *dev, int id, bool *val)
{
+ struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
+ if (!priv->detected)
+ return -EPERM;
+
if (!ops->get_bool)
return -ENOSYS;
@@ -46,8 +64,12 @@ int sysinfo_get_bool(struct udevice *dev, int id, bool *val)
int sysinfo_get_int(struct udevice *dev, int id, int *val)
{
+ struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
+ if (!priv->detected)
+ return -EPERM;
+
if (!ops->get_int)
return -ENOSYS;
@@ -56,8 +78,12 @@ int sysinfo_get_int(struct udevice *dev, int id, int *val)
int sysinfo_get_str(struct udevice *dev, int id, size_t size, char *val)
{
+ struct sysinfo_priv *priv = dev_get_uclass_priv(dev);
struct sysinfo_ops *ops = sysinfo_get_ops(dev);
+ if (!priv->detected)
+ return -EPERM;
+
if (!ops->get_str)
return -ENOSYS;
@@ -68,4 +94,5 @@ UCLASS_DRIVER(sysinfo) = {
.id = UCLASS_SYSINFO,
.name = "sysinfo",
.post_bind = dm_scan_fdt_dev,
+ .per_device_auto = sizeof(bool),
};
diff --git a/env/Kconfig b/env/Kconfig
index 1b7906c..1411f9e 100644
--- a/env/Kconfig
+++ b/env/Kconfig
@@ -670,6 +670,24 @@ config DELAY_ENVIRONMENT
later by U-Boot code. With CONFIG_OF_CONTROL this is instead
controlled by the value of /config/load-environment.
+config ENV_IMPORT_FDT
+ bool "Amend environment by FDT properties"
+ depends on OF_CONTROL
+ help
+ If selected, after the environment has been loaded from its
+ persistent location, the "env_fdt_path" variable is looked
+ up and used as a path to a node in the control DTB. The
+ property/value pairs in that node is then used to update the
+ run-time environment. This can be useful to use the same
+ U-Boot binary with different board variants.
+
+config ENV_FDT_PATH
+ string "Default value for env_fdt_path variable"
+ depends on ENV_IMPORT_FDT
+ default "/config/environment"
+ help
+ The initial value of the env_fdt_path variable.
+
config ENV_APPEND
bool "Always append the environment with new data"
default n
diff --git a/env/common.c b/env/common.c
index 49bbb05..81e9e0b 100644
--- a/env/common.c
+++ b/env/common.c
@@ -20,6 +20,7 @@
#include <errno.h>
#include <malloc.h>
#include <u-boot/crc.h>
+#include <dm/ofnode.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -334,3 +335,32 @@ int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf,
return found;
}
#endif
+
+#ifdef CONFIG_ENV_IMPORT_FDT
+void env_import_fdt(void)
+{
+ const char *path;
+ struct ofprop prop;
+ ofnode node;
+ int res;
+
+ path = env_get("env_fdt_path");
+ if (!path || !path[0])
+ return;
+
+ node = ofnode_path(path);
+ if (!ofnode_valid(node)) {
+ printf("Warning: device tree node '%s' not found\n", path);
+ return;
+ }
+
+ for (res = ofnode_get_first_property(node, &prop);
+ !res;
+ res = ofnode_get_next_property(&prop)) {
+ const char *name, *val;
+
+ val = ofnode_get_property_by_prop(&prop, &name, NULL);
+ env_set(name, val);
+ }
+}
+#endif
diff --git a/include/env.h b/include/env.h
index b5731e4..d5e2bcb 100644
--- a/include/env.h
+++ b/include/env.h
@@ -375,4 +375,19 @@ int env_get_char(int index);
* This is used for those unfortunate archs with crappy toolchains
*/
void env_reloc(void);
+
+
+/**
+ * env_import_fdt() - Import environment values from device tree blob
+ *
+ * This uses the value of the environment variable "env_fdt_path" as a
+ * path to an fdt node, whose property/value pairs are added to the
+ * environment.
+ */
+#ifdef CONFIG_ENV_IMPORT_FDT
+void env_import_fdt(void);
+#else
+static inline void env_import_fdt(void) {}
+#endif
+
#endif
diff --git a/include/env_default.h b/include/env_default.h
index ea31a8e..1ddd64b 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -103,6 +103,9 @@ const uchar default_environment[] = {
#ifdef CONFIG_SYS_SOC
"soc=" CONFIG_SYS_SOC "\0"
#endif
+#ifdef CONFIG_ENV_IMPORT_FDT
+ "env_fdt_path=" CONFIG_ENV_FDT_PATH "\0"
+#endif
#endif
#if defined(CONFIG_BOOTCOUNT_BOOTLIMIT) && (CONFIG_BOOTCOUNT_BOOTLIMIT > 0)
"bootlimit=" __stringify(CONFIG_BOOTCOUNT_BOOTLIMIT)"\0"
diff --git a/include/fdt_support.h b/include/fdt_support.h
index 46eb1db..e2a4689 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -185,6 +185,16 @@ int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name);
*/
int ft_board_setup(void *blob, struct bd_info *bd);
+/**
+ * board_fdt_chosen_bootargs() - Arbitrarily amend fdt kernel command line
+ *
+ * This is used for late modification of kernel command line arguments just
+ * before they are added into the /chosen node in flat device tree.
+ *
+ * @return: pointer to kernel command line arguments in memory
+ */
+char *board_fdt_chosen_bootargs(void);
+
/*
* The keystone2 SOC requires all 32 bit aliased addresses to be converted
* to their 36 physical format. This has to happen after all fdt nodes
diff --git a/include/sysinfo.h b/include/sysinfo.h
index 8054d4d..b140d74 100644
--- a/include/sysinfo.h
+++ b/include/sysinfo.h
@@ -60,7 +60,8 @@ struct sysinfo_ops {
* This operation might take a long time (e.g. read from EEPROM,
* check the presence of a device on a bus etc.), hence this is not
* done in the probe() method, but later during operation in this
- * dedicated method.
+ * dedicated method. This method will be called before any other
+ * methods.
*
* Return: 0 if OK, -ve on error.
*/
@@ -104,7 +105,7 @@ struct sysinfo_ops {
* get_fit_loadable - Get the name of an image to load from FIT
* This function can be used to provide the image names based on runtime
* detection. A classic use-case would when DTBOs are used to describe
- * additionnal daughter cards.
+ * additional daughter cards.
*
* @dev: The sysinfo instance to gather the data.
* @index: Index of the image. Starts at 0 and gets incremented
@@ -127,6 +128,9 @@ struct sysinfo_ops {
*
* @dev: The device containing the information
*
+ * This function must be called before any other accessor function for this
+ * device.
+ *
* Return: 0 if OK, -ve on error.
*/
int sysinfo_detect(struct udevice *dev);
@@ -138,7 +142,8 @@ int sysinfo_detect(struct udevice *dev);
* @id: A unique identifier for the bool value to be read.
* @val: Pointer to a buffer that receives the value read.
*
- * Return: 0 if OK, -ve on error.
+ * Return: 0 if OK, -EPERM if called before sysinfo_detect(), else -ve on
+ * error.
*/
int sysinfo_get_bool(struct udevice *dev, int id, bool *val);
@@ -149,7 +154,8 @@ int sysinfo_get_bool(struct udevice *dev, int id, bool *val);
* @id: A unique identifier for the int value to be read.
* @val: Pointer to a buffer that receives the value read.
*
- * Return: 0 if OK, -ve on error.
+ * Return: 0 if OK, -EPERM if called before sysinfo_detect(), else -ve on
+ * error.
*/
int sysinfo_get_int(struct udevice *dev, int id, int *val);
@@ -161,7 +167,8 @@ int sysinfo_get_int(struct udevice *dev, int id, int *val);
* @size: The size of the buffer to receive the string data.
* @val: Pointer to a buffer that receives the value read.
*
- * Return: 0 if OK, -ve on error.
+ * Return: 0 if OK, -EPERM if called before sysinfo_detect(), else -ve on
+ * error.
*/
int sysinfo_get_str(struct udevice *dev, int id, size_t size, char *val);
@@ -173,7 +180,8 @@ int sysinfo_get_str(struct udevice *dev, int id, size_t size, char *val);
* function that returns the unique device. This is especially useful for use
* in sysinfo files.
*
- * Return: 0 if OK, -ve on error.
+ * Return: 0 if OK, -EPERM if called before sysinfo_detect(), else -ve on
+ * error.
*/
int sysinfo_get(struct udevice **devp);
@@ -181,7 +189,7 @@ int sysinfo_get(struct udevice **devp);
* sysinfo_get_fit_loadable - Get the name of an image to load from FIT
* This function can be used to provide the image names based on runtime
* detection. A classic use-case would when DTBOs are used to describe
- * additionnal daughter cards.
+ * additional daughter cards.
*
* @dev: The sysinfo instance to gather the data.
* @index: Index of the image. Starts at 0 and gets incremented
@@ -190,8 +198,8 @@ int sysinfo_get(struct udevice **devp);
* @strp: A pointer to string. Untouched if the function fails
*
*
- * Return: 0 if OK, -ENOENT if no loadable is available else -ve on
- * error.
+ * Return: 0 if OK, -EPERM if called before sysinfo_detect(), -ENOENT if no
+ * loadable is available else -ve on error.
*/
int sysinfo_get_fit_loadable(struct udevice *dev, int index, const char *type,
const char **strp);
diff --git a/test/dm/Makefile b/test/dm/Makefile
index e7cb1ee..c964461 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -96,6 +96,7 @@ obj-$(CONFIG_SPMI) += spmi.o
obj-y += syscon.o
obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o
obj-$(CONFIG_SYSINFO) += sysinfo.o
+obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o
obj-$(CONFIG_TEE) += tee.o
obj-$(CONFIG_TIMER) += timer.o
obj-$(CONFIG_DM_USB) += usb.o
diff --git a/test/dm/sysinfo-gpio.c b/test/dm/sysinfo-gpio.c
new file mode 100644
index 0000000..2e494b3
--- /dev/null
+++ b/test/dm/sysinfo-gpio.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Sean Anderson <sean.anderson@seco.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <sysinfo.h>
+#include <asm/gpio.h>
+#include <dm/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+static int dm_test_sysinfo_gpio(struct unit_test_state *uts)
+{
+ char buf[64];
+ int val;
+ struct udevice *sysinfo, *gpio;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_SYSINFO, "sysinfo-gpio",
+ &sysinfo));
+ ut_assertok(uclass_get_device_by_name(UCLASS_GPIO, "base-gpios", &gpio));
+
+ /*
+ * Set up pins: pull-up (1), pull-down (0) and floating (2). This should
+ * result in digits 2 0 1, i.e. 2 * 9 + 1 * 3 = 19
+ */
+ sandbox_gpio_set_flags(gpio, 15, GPIOD_EXT_PULL_UP);
+ sandbox_gpio_set_flags(gpio, 16, GPIOD_EXT_PULL_DOWN);
+ sandbox_gpio_set_flags(gpio, 17, 0);
+ ut_assertok(sysinfo_detect(sysinfo));
+ ut_assertok(sysinfo_get_int(sysinfo, SYSINFO_ID_BOARD_MODEL, &val));
+ ut_asserteq(19, val);
+ ut_assertok(sysinfo_get_str(sysinfo, SYSINFO_ID_BOARD_MODEL, sizeof(buf),
+ buf));
+ ut_asserteq_str("rev_a", buf);
+
+ /*
+ * Set up pins: floating (2), pull-up (1) and pull-down (0). This should
+ * result in digits 0 1 2, i.e. 1 * 3 + 2 = 5
+ */
+ sandbox_gpio_set_flags(gpio, 15, 0);
+ sandbox_gpio_set_flags(gpio, 16, GPIOD_EXT_PULL_UP);
+ sandbox_gpio_set_flags(gpio, 17, GPIOD_EXT_PULL_DOWN);
+ ut_assertok(sysinfo_detect(sysinfo));
+ ut_assertok(sysinfo_get_int(sysinfo, SYSINFO_ID_BOARD_MODEL, &val));
+ ut_asserteq(5, val);
+ ut_assertok(sysinfo_get_str(sysinfo, SYSINFO_ID_BOARD_MODEL, sizeof(buf),
+ buf));
+ ut_asserteq_str("foo", buf);
+
+ /*
+ * Set up pins: floating (2), pull-up (1) and pull-down (0). This should
+ * result in digits 1 2 0, i.e. 1 * 9 + 2 * 3 = 15
+ */
+ sandbox_gpio_set_flags(gpio, 15, GPIOD_EXT_PULL_DOWN);
+ sandbox_gpio_set_flags(gpio, 16, 0);
+ sandbox_gpio_set_flags(gpio, 17, GPIOD_EXT_PULL_UP);
+ ut_assertok(sysinfo_detect(sysinfo));
+ ut_assertok(sysinfo_get_int(sysinfo, SYSINFO_ID_BOARD_MODEL, &val));
+ ut_asserteq(15, val);
+ ut_assertok(sysinfo_get_str(sysinfo, SYSINFO_ID_BOARD_MODEL, sizeof(buf),
+ buf));
+ ut_asserteq_str("unknown", buf);
+
+ return 0;
+}
+DM_TEST(dm_test_sysinfo_gpio, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/dm/sysinfo.c b/test/dm/sysinfo.c
index 4aaa9e8..96b3a8e 100644
--- a/test/dm/sysinfo.c
+++ b/test/dm/sysinfo.c
@@ -17,40 +17,45 @@
static int dm_test_sysinfo(struct unit_test_state *uts)
{
struct udevice *sysinfo;
- bool called_detect;
+ bool called_detect = false;
char str[64];
int i;
ut_assertok(sysinfo_get(&sysinfo));
ut_assert(sysinfo);
- sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT, &called_detect);
+ ut_asserteq(-EPERM, sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT,
+ &called_detect));
ut_assert(!called_detect);
sysinfo_detect(sysinfo);
- sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT, &called_detect);
+ ut_assertok(sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT,
+ &called_detect));
ut_assert(called_detect);
- sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str), str);
+ ut_assertok(sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str),
+ str));
ut_assertok(strcmp(str, "R'lyeh"));
- sysinfo_get_int(sysinfo, INT_TEST1, &i);
+ ut_assertok(sysinfo_get_int(sysinfo, INT_TEST1, &i));
ut_asserteq(0, i);
- sysinfo_get_int(sysinfo, INT_TEST2, &i);
+ ut_assertok(sysinfo_get_int(sysinfo, INT_TEST2, &i));
ut_asserteq(100, i);
- sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str), str);
+ ut_assertok(sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str),
+ str));
ut_assertok(strcmp(str, "Carcosa"));
- sysinfo_get_int(sysinfo, INT_TEST1, &i);
+ ut_assertok(sysinfo_get_int(sysinfo, INT_TEST1, &i));
ut_asserteq(1, i);
- sysinfo_get_int(sysinfo, INT_TEST2, &i);
+ ut_assertok(sysinfo_get_int(sysinfo, INT_TEST2, &i));
ut_asserteq(99, i);
- sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str), str);
+ ut_assertok(sysinfo_get_str(sysinfo, STR_VACATIONSPOT, sizeof(str),
+ str));
ut_assertok(strcmp(str, "Yuggoth"));
return 0;
diff --git a/test/env/Makefile b/test/env/Makefile
index 5c8eae3..9a98fd4 100644
--- a/test/env/Makefile
+++ b/test/env/Makefile
@@ -5,3 +5,4 @@
obj-y += cmd_ut_env.o
obj-y += attr.o
obj-y += hashtable.o
+obj-$(CONFIG_ENV_IMPORT_FDT) += fdt.o
diff --git a/test/env/fdt.c b/test/env/fdt.c
new file mode 100644
index 0000000..30bfa88
--- /dev/null
+++ b/test/env/fdt.c
@@ -0,0 +1,20 @@
+#include <common.h>
+#include <command.h>
+#include <env_attr.h>
+#include <test/env.h>
+#include <test/ut.h>
+
+static int env_test_fdt_import(struct unit_test_state *uts)
+{
+ const char *val;
+
+ val = env_get("from_fdt");
+ ut_assertnonnull(val);
+ ut_asserteq_str("yes", val);
+
+ val = env_get("fdt_env_path");
+ ut_assertnull(val);
+
+ return 0;
+}
+ENV_TEST(env_test_fdt_import, 0);