From 430e136dc1398546ad2b1db08692e9edac480cc8 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 20 Apr 2021 10:50:54 -0400 Subject: [PATCH 01/17] dm: gpio: Fix gpio_get_list_count failing with livetree of_parse_phandle_with_args (called by dev_read_phandle_with_args) does not support getting the length of a phandle list by using the index -1. Instead, use dev_count_phandle_with_args which supports exactly this use-case. Fixes: 8558217153 ("gpio: Convert to use APIs which support live DT") Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- drivers/gpio/gpio-uclass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index e4e7f58c39..131099cc17 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); } From eed0a7a3e6087d038fccea18676e285d9807b644 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 20 Apr 2021 10:50:55 -0400 Subject: [PATCH 02/17] sysinfo: Use global sysinfo IDs for existing sysinfo drivers Since 07c9e683a4 ("smbios: Allow a few values to come from sysinfo") there are common global sysinfo IDs. This patch moved existing IDs above SYSINFO_ID_USER. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- drivers/sysinfo/gazerbeam.h | 8 +++++--- drivers/sysinfo/sandbox.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/sysinfo/gazerbeam.h b/drivers/sysinfo/gazerbeam.h index 171729d203..6bf3c0098d 100644 --- a/drivers/sysinfo/gazerbeam.h +++ b/drivers/sysinfo/gazerbeam.h @@ -5,10 +5,12 @@ * */ +#include + 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/sandbox.h b/drivers/sysinfo/sandbox.h index 2cff494f56..d9c5804c26 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, From 4d65c6bcd71ab2a03a5b7fff0ecf22d068597b25 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 20 Apr 2021 10:50:56 -0400 Subject: [PATCH 03/17] sysinfo: Require that sysinfo_detect be called before other methods This has the uclass enforce calling detect() before other methods. This allows drivers to cache information in detect() and perform (cheaper) retrieval in the other accessors. This also modifies the only instance where this sequencing was not followed. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- common/spl/spl_fit.c | 4 ++++ drivers/sysinfo/sysinfo-uclass.c | 29 ++++++++++++++++++++++++++++- include/sysinfo.h | 26 +++++++++++++++++--------- test/dm/sysinfo.c | 25 +++++++++++++++---------- 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 4288f571fc..caddf51196 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/drivers/sysinfo/sysinfo-uclass.c b/drivers/sysinfo/sysinfo-uclass.c index 6df58fe160..4a660dfd15 100644 --- a/drivers/sysinfo/sysinfo-uclass.c +++ b/drivers/sysinfo/sysinfo-uclass.c @@ -8,6 +8,10 @@ #include #include +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/include/sysinfo.h b/include/sysinfo.h index 8054d4d4a1..b140d742e9 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/sysinfo.c b/test/dm/sysinfo.c index 4aaa9e85bc..96b3a8ebab 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; From 54aa07fdfc01ac5abff342699df269f6f869fbe0 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 20 Apr 2021 10:50:57 -0400 Subject: [PATCH 04/17] sysinfo: Add gpio-sysinfo driver This uses the newly-added dm_gpio_get_values_as_int_base3 function to implement a sysinfo device. The revision map is stored in the device tree. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- .../sysinfo/gpio-sysinfo.txt | 37 +++++ drivers/sysinfo/Kconfig | 8 + drivers/sysinfo/Makefile | 1 + drivers/sysinfo/gpio.c | 141 ++++++++++++++++++ 4 files changed, 187 insertions(+) create mode 100644 doc/device-tree-bindings/sysinfo/gpio-sysinfo.txt create mode 100644 drivers/sysinfo/gpio.c 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 0000000000..b5739d94e9 --- /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/sysinfo/Kconfig b/drivers/sysinfo/Kconfig index 85c1e81e41..381dcd8844 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 6d04fcba1d..d9f708b7ea 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/gpio.c b/drivers/sysinfo/gpio.c new file mode 100644 index 0000000000..1d7f050998 --- /dev/null +++ b/drivers/sysinfo/gpio.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Sean Anderson + */ + +#include +#include +#include +#include +#include +#include + +/** + * 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, +}; From 1cbfed8d3e9254d7e2a9466498ef867f7cb3f4cd Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 20 Apr 2021 10:50:58 -0400 Subject: [PATCH 05/17] test: Add gpio-sysinfo test This adds a test for the gpio-sysinfo driver. Signed-off-by: Sean Anderson Reviewed-by: Simon Glass --- arch/sandbox/dts/test.dts | 7 +++ configs/sandbox64_defconfig | 1 + configs/sandbox_defconfig | 1 + configs/sandbox_flattree_defconfig | 1 + configs/sandbox_noinst_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + test/dm/Makefile | 1 + test/dm/sysinfo-gpio.c | 69 ++++++++++++++++++++++++++++++ 8 files changed, 82 insertions(+) create mode 100644 test/dm/sysinfo-gpio.c diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 4fde923e9a..6fd56c351c 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1526,6 +1526,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/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 8a7e519847..80c5be2067 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -204,6 +204,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 00befc8b40..570af61cbd 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -245,6 +245,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 97ac46d21f..853c9440ea 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 2e7b138558..c7fc98b556 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 a71349432e..87223a54d8 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/test/dm/Makefile b/test/dm/Makefile index e7cb1eec96..c9644617a1 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 0000000000..2e494b3f34 --- /dev/null +++ b/test/dm/sysinfo-gpio.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Sean Anderson + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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); From 95fd9772011f29fad2c40fbc3060b5dac042152c Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 21 Apr 2021 11:06:54 +0200 Subject: [PATCH 06/17] env: allow environment to be amended from control dtb It can be useful to use the same U-Boot binary for multiple purposes, say the normal one, one for developers that allow breaking into the U-Boot shell, and one for use during bootstrapping which runs a special-purpose bootcmd. Or one can have several board variants that can share almost all boot logic, but just needs a few tweaks in the variables used by the boot script. To that end, allow the control dtb to contain a /config/enviroment node (or whatever one puts in fdt_env_path variable), whose property/value pairs are used to update the run-time environment after it has been loaded from its persistent location. The indirection via fdt_env_path is for maximum flexibility - for example, should the user wish (or board logic dictate) that the values in the DTB should no longer be applied, one simply needs to delete the fdt_env_path variable; that can even be done automatically by including a fdt_env_path = ""; property in the DTB node. Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes Acked-by: Joe Hershberger --- common/board_r.c | 2 ++ env/Kconfig | 18 ++++++++++++++++++ env/common.c | 30 ++++++++++++++++++++++++++++++ include/env.h | 15 +++++++++++++++ include/env_default.h | 3 +++ 5 files changed, 68 insertions(+) diff --git a/common/board_r.c b/common/board_r.c index c835ff8e26..3f82404772 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/env/Kconfig b/env/Kconfig index 1b7906cf72..1411f9e815 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 49bbb05eec..81e9e0b2aa 100644 --- a/env/common.c +++ b/env/common.c @@ -20,6 +20,7 @@ #include #include #include +#include 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 b5731e4b9a..d5e2bcb530 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 ea31a8eddf..1ddd64ba8f 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" From 8c72842af5f81826b344c26b1c28c3122edb909e Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 21 Apr 2021 11:06:55 +0200 Subject: [PATCH 07/17] sandbox: add test of CONFIG_ENV_IMPORT_FDT Check that a variable defined in /config/environment is found in the run-time environment, and that clearing fdt_env_path from within that node works. Reviewed-by: Simon Glass Signed-off-by: Rasmus Villemoes Acked-by: Joe Hershberger [trini: Conditionalize the test being linked in] Signed-off-by: Tom Rini --- arch/sandbox/dts/test.dts | 7 +++++++ configs/sandbox64_defconfig | 1 + configs/sandbox_defconfig | 1 + test/env/Makefile | 1 + test/env/fdt.c | 20 ++++++++++++++++++++ 5 files changed, 30 insertions(+) create mode 100644 test/env/fdt.c diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 6fd56c351c..fe26ced31d 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>; diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 80c5be2067..9a373bab6f 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 diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 570af61cbd..bdbf714e2b 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 diff --git a/test/env/Makefile b/test/env/Makefile index 5c8eae31b0..9a98fd4796 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 0000000000..30bfa88c35 --- /dev/null +++ b/test/env/fdt.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include + +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); From 653cd92d66771cf1fbd1b7612b06a0874d316654 Mon Sep 17 00:00:00 2001 From: Farhan Ali Date: Fri, 26 Feb 2021 10:17:33 -0800 Subject: [PATCH 08/17] cmd: gpt: Add option to write GPT partitions to environment variable This change would enhance the existing 'gpt read' command to allow (optionally) writing of the read GPT partitions to an environment variable in the UBOOT partitions layout format. This would allow users to easily change the overall partition settings by editing said variable and then using the variable in the 'gpt write' and 'gpt verify' commands. Signed-off-by: Farhan Ali Cc: Simon Glass Cc: Heinrich Schuchardt Cc: Corneliu Doban Cc: Rayagonda Kokatanur Cc: Rasmus Villemoes Reviewed-by: Simon Glass --- cmd/gpt.c | 46 ++++++++++++++++++++++++++++++++++++++-------- doc/README.gpt | 17 +++++++++++++++++ 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/cmd/gpt.c b/cmd/gpt.c index 76a95ade6c..17f2b839d7 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; - ret = get_gpt_info(dev_desc); - if (ret > 0) { - print_gpt_info(); + 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); + + 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 \n" + " gpt read []\n" " - read GPT into a data structure for manipulation\n" + " - read GPT partitions into environment variable\n" " gpt swap \n" " - change all partitions named name1 to name2\n" " and vice-versa\n" diff --git a/doc/README.gpt b/doc/README.gpt index ac975f66b8..91e397d06f 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: ==================== From f0b21ebd417cfe75f266b4dc16318bb3581783b9 Mon Sep 17 00:00:00 2001 From: Niko Mauno Date: Mon, 22 Feb 2021 19:18:51 +0000 Subject: [PATCH 09/17] fdt_support.c: Allow late kernel cmdline modification By declaring board-specific board_fdt_chosen_bootargs() the kernel command line arguments can be adjusted before injecting to flat dt chosen node. Signed-off-by: Niko Mauno --- common/fdt_support.c | 12 +++++++++++- include/fdt_support.h | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/common/fdt_support.c b/common/fdt_support.c index e624bbdf40..7eb5ba3bb2 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/include/fdt_support.h b/include/fdt_support.h index 46eb1dbbb2..e2a4689cd8 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 From edd9ad81947d2136c71657be88d6cc35a56bd22f Mon Sep 17 00:00:00 2001 From: Green Wan Date: Sun, 2 May 2021 23:23:04 -0700 Subject: [PATCH 10/17] riscv: cpu: Add callback to init each core Add a callback harts_early_init() to start.S to allow different riscv hart perform setup code for each hart as early as possible. Since all the harts enter the callback, they must be able to run the same setup. Signed-off-by: Green Wan Reviewed-by: Rick Chen Reviewed-by: Bin Meng --- arch/riscv/cpu/cpu.c | 11 +++++++++++ arch/riscv/cpu/start.S | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index 85592f5bee..296e458db4 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -140,3 +140,14 @@ int arch_early_init_r(void) { return riscv_cpu_probe(); } + +/** + * harts_early_init() - A callback function called by start.S to configure + * feature settings of each hart. + * + * In a multi-core system, memory access shall be careful here, it shall + * take care of race conditions. + */ +__weak void harts_early_init(void) +{ +} diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S index 8589509e01..308b0a97a5 100644 --- a/arch/riscv/cpu/start.S +++ b/arch/riscv/cpu/start.S @@ -117,6 +117,10 @@ call_board_init_f_0: mv sp, a0 #endif + /* Configure proprietary settings and customized CSRs of harts */ +call_harts_early_init: + jal harts_early_init + #ifndef CONFIG_XIP /* * Pick hart to initialize global data and run U-Boot. The other harts From bc8bbb77f74f21582b3bfd790334397757f88575 Mon Sep 17 00:00:00 2001 From: Green Wan Date: Sun, 2 May 2021 23:23:05 -0700 Subject: [PATCH 11/17] riscv: cpu: fu740: clear feature disable CSR Clear feature disable CSR to turn on all features of hart. The detail is specified at section, 'SiFive Feature Disable CSR', in user manual https://sifive.cdn.prismic.io/sifive/aee0dd4c-d156-496e-a6c4-db0cf54bbe68_sifive_U74MC_rtl_full_20G1.03.00_manual.pdf Signed-off-by: Green Wan Reviewed-by: Sean Anderson Reviewed-by: Bin Meng Reviewed-by: Rick Chen --- arch/riscv/cpu/fu540/spl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/riscv/cpu/fu540/spl.c b/arch/riscv/cpu/fu540/spl.c index 45657b7909..1740ef98b6 100644 --- a/arch/riscv/cpu/fu540/spl.c +++ b/arch/riscv/cpu/fu540/spl.c @@ -6,6 +6,9 @@ #include #include +#include + +#define CSR_U74_FEATURE_DISABLE 0x7c1 int spl_soc_init(void) { @@ -21,3 +24,15 @@ int spl_soc_init(void) return 0; } + +void harts_early_init(void) +{ + /* + * Feature Disable CSR + * + * Clear feature disable CSR to '0' to turn on all features for + * each core. This operation must be in M-mode. + */ + if (CONFIG_IS_ENABLED(RISCV_MMODE)) + csr_write(CSR_U74_FEATURE_DISABLE, 0); +} From 1412b8d48a920f1a4f5eac256814d25c320fb9b6 Mon Sep 17 00:00:00 2001 From: Dylan Jhong Date: Thu, 1 Apr 2021 16:48:51 +0800 Subject: [PATCH 12/17] atcspi200: Add timeout mechanism in spi_xfer() Adding timeout mechanism to avoid spi driver from stucking in the while loop in __atcspi200_spi_xfer(). Signed-off-by: Dylan Jhong Reviewed-by: Leo Yu-Chi Liang Reviewed-by: Rick Chen --- drivers/spi/atcspi200_spi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/spi/atcspi200_spi.c b/drivers/spi/atcspi200_spi.c index 634cd56561..775b9ffc25 100644 --- a/drivers/spi/atcspi200_spi.c +++ b/drivers/spi/atcspi200_spi.c @@ -201,7 +201,7 @@ static int __atcspi200_spi_xfer(struct nds_spi_slave *ns, size_t cmd_len = ns->cmd_len; unsigned long data_len = bitlen / 8; int rf_cnt; - int ret = 0; + int ret = 0, timeout = 0; max_tran_len = ns->max_transfer_length; switch (flags) { @@ -243,11 +243,12 @@ static int __atcspi200_spi_xfer(struct nds_spi_slave *ns, ns->tran_len = tran_len; num_blks = DIV_ROUND_UP(tran_len , CHUNK_SIZE); num_bytes = (tran_len) % CHUNK_SIZE; + timeout = SPI_TIMEOUT; if(num_bytes == 0) num_bytes = CHUNK_SIZE; __atcspi200_spi_start(ns); - while (num_blks) { + while (num_blks && (timeout--)) { event = in_le32(&ns->regs->status); if ((event & TXEPTY) && (data_out)) { __nspi_espi_tx(ns, dout); @@ -269,6 +270,11 @@ static int __atcspi200_spi_xfer(struct nds_spi_slave *ns, din = (unsigned char *)din + rx_bytes; } } + + if (!timeout) { + debug("spi_xfer: %s() timeout\n", __func__); + break; + } } data_len -= tran_len; From 91e4b7516d84cefab7324765b3c8d6a909185ce2 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 9 Apr 2021 10:48:14 +0000 Subject: [PATCH 13/17] cmd/exception: support ebreak exception on RISC-V The ebreak instruction should generate a breakpoint exception. Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng Reviewed-by: Rick Chen --- cmd/riscv/exception.c | 10 ++++++++++ doc/usage/exception.rst | 3 +++ 2 files changed, 13 insertions(+) diff --git a/cmd/riscv/exception.c b/cmd/riscv/exception.c index 9687cec812..7a08061d12 100644 --- a/cmd/riscv/exception.c +++ b/cmd/riscv/exception.c @@ -8,6 +8,13 @@ #include #include +static int do_ebreak(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + asm volatile ("ebreak\n"); + return CMD_RET_FAILURE; +} + static int do_unaligned(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -28,6 +35,8 @@ static int do_undefined(struct cmd_tbl *cmdtp, int flag, int argc, } static struct cmd_tbl cmd_sub[] = { + U_BOOT_CMD_MKENT(ebreak, CONFIG_SYS_MAXARGS, 1, do_ebreak, + "", ""), U_BOOT_CMD_MKENT(unaligned, CONFIG_SYS_MAXARGS, 1, do_unaligned, "", ""), U_BOOT_CMD_MKENT(undefined, CONFIG_SYS_MAXARGS, 1, do_undefined, @@ -37,6 +46,7 @@ static struct cmd_tbl cmd_sub[] = { static char exception_help_text[] = "\n" " The following exceptions are available:\n" + " ebreak - breakpoint\n" " undefined - illegal instruction\n" " unaligned - load address misaligned\n" ; diff --git a/doc/usage/exception.rst b/doc/usage/exception.rst index db1490f005..27df88bd5c 100644 --- a/doc/usage/exception.rst +++ b/doc/usage/exception.rst @@ -31,6 +31,9 @@ type **RISC-V:** + ebreak + breakpoint exception + unaligned load address misaligned From b8db1c138861b7d35d2206af6a555bab05a096a0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 24 Apr 2021 10:04:57 +1200 Subject: [PATCH 14/17] x86: Correct regwidth prompt in cbsysinfo This should be 'regwidth', not 'baud'. Fix it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- cmd/x86/cbsysinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/x86/cbsysinfo.c b/cmd/x86/cbsysinfo.c index a0db0ad364..34fdaf5b1b 100644 --- a/cmd/x86/cbsysinfo.c +++ b/cmd/x86/cbsysinfo.c @@ -205,7 +205,7 @@ static void show_table(struct sysinfo_t *info, bool verbose) print_hex(">type", ser->type); print_addr(">base", ser->baseaddr); print_dec(">baud", ser->baud); - print_hex(">baud", ser->regwidth); + print_hex(">regwidth", ser->regwidth); print_dec(">input_hz", ser->input_hertz); print_addr(">PCI addr", ser->uart_pci_addr); } From 9cea9abbe4f3c2ccc69e621d39a19338815e9827 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Apr 2021 17:40:07 +0800 Subject: [PATCH 15/17] doc: develop: Convert README.virtio to reST This converts the existing README.virtio to reST, and puts it under the develop/driver-model/ directory. Signed-off-by: Bin Meng --- doc/develop/driver-model/index.rst | 1 + .../driver-model/virtio.rst} | 90 +++++++++++++------ 2 files changed, 63 insertions(+), 28 deletions(-) rename doc/{README.virtio => develop/driver-model/virtio.rst} (86%) diff --git a/doc/develop/driver-model/index.rst b/doc/develop/driver-model/index.rst index fd4575db9b..10a76256b0 100644 --- a/doc/develop/driver-model/index.rst +++ b/doc/develop/driver-model/index.rst @@ -27,3 +27,4 @@ subsystems soc-framework spi-howto usb-info + virtio diff --git a/doc/README.virtio b/doc/develop/driver-model/virtio.rst similarity index 86% rename from doc/README.virtio rename to doc/develop/driver-model/virtio.rst index d3652f2e2f..8ac9c94caf 100644 --- a/doc/README.virtio +++ b/doc/develop/driver-model/virtio.rst @@ -1,11 +1,10 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# Copyright (C) 2018, Bin Meng +.. SPDX-License-Identifier: GPL-2.0+ +.. sectionauthor:: Bin Meng VirtIO Support ============== -This document describes the information about U-Boot support for VirtIO [1] +This document describes the information about U-Boot support for VirtIO_ devices, including supported boards, build instructions, driver details etc. What's VirtIO? @@ -15,7 +14,7 @@ just the guest's device driver "knows" it is running in a virtual environment, and cooperates with the hypervisor. This enables guests to get high performance network and disk operations, and gives most of the performance benefits of paravirtualization. In the U-Boot case, the guest is U-Boot itself, while the -virtual environment are normally QEMU [2] targets like ARM, RISC-V and x86. +virtual environment are normally QEMU_ targets like ARM, RISC-V and x86. Status ------ @@ -49,6 +48,8 @@ Building U-Boot for pre-configured QEMU targets is no different from others. For example, we can do the following with the CROSS_COMPILE environment variable being properly set to a working toolchain for ARM: +.. code-block:: bash + $ make qemu_arm_defconfig $ make @@ -56,11 +57,13 @@ You can even create a QEMU ARM target with VirtIO devices showing up on both MMIO and PCI buses. In this case, you can enable the PCI transport driver from 'make menuconfig': -Device Drivers ---> - ... - VirtIO Drivers ---> - ... - [*] PCI driver for virtio devices +.. code-block:: none + + Device Drivers ---> + ... + VirtIO Drivers ---> + ... + [*] PCI driver for virtio devices Other drivers are at the same location and can be tuned to suit the needs. @@ -74,6 +77,8 @@ Testing The following QEMU command line is used to get U-Boot up and running with VirtIO net and block devices on ARM. +.. code-block:: bash + $ qemu-system-arm -nographic -machine virt -bios u-boot.bin \ -netdev tap,ifname=tap0,id=net0 \ -device virtio-net-device,netdev=net0 \ @@ -82,6 +87,8 @@ VirtIO net and block devices on ARM. On x86, command is slightly different to create PCI VirtIO devices. +.. code-block:: bash + $ qemu-system-i386 -nographic -bios u-boot.rom \ -netdev tap,ifname=tap0,id=net0 \ -device virtio-net-pci,netdev=net0 \ @@ -93,6 +100,8 @@ parameters. It is also possible to specify both MMIO and PCI VirtIO devices. For example, the following commnad creates 3 VirtIO devices, with 1 on MMIO and 2 on PCI bus. +.. code-block:: bash + $ qemu-system-arm -nographic -machine virt -bios u-boot.bin \ -netdev tap,ifname=tap0,id=net0 \ -device virtio-net-pci,netdev=net0 \ @@ -104,6 +113,8 @@ and 2 on PCI bus. By default QEMU creates VirtIO legacy devices by default. To create non-legacy (aka modern) devices, pass additional device property/value pairs like below: +.. code-block:: bash + $ qemu-system-i386 -nographic -bios u-boot.rom \ -netdev tap,ifname=tap0,id=net0 \ -device virtio-net-pci,netdev=net0,disable-legacy=true,disable-modern=false \ @@ -112,6 +123,8 @@ By default QEMU creates VirtIO legacy devices by default. To create non-legacy A 'virtio' command is provided in U-Boot shell. +.. code-block:: none + => virtio virtio - virtio block devices sub-system @@ -127,10 +140,14 @@ A 'virtio' command is provided in U-Boot shell. To probe all the VirtIO devices, type: +.. code-block:: none + => virtio scan Then we can show the connected block device details by: +.. code-block:: none + => virtio info Device 0: QEMU VirtIO Block Device Type: Hard Disk @@ -138,6 +155,8 @@ Then we can show the connected block device details by: And list the directories and files on the disk by: +.. code-block:: none + => ls virtio 0 / 4096 . 4096 .. @@ -167,6 +186,8 @@ Driver Internals ---------------- There are 3 level of drivers in the VirtIO driver family. +.. code-block:: none + +---------------------------------------+ | virtio device drivers | | +-------------+ +------------+ | @@ -199,20 +220,26 @@ The transport drivers provide a set of ops (struct dm_virtio_ops) for the real virtio device driver to call. These ops APIs's parameter is designed to remind the caller to pass the correct 'struct udevice' id of the virtio device, eg: -int virtio_get_status(struct udevice *vdev, u8 *status) +.. code-block:: C + + int virtio_get_status(struct udevice *vdev, u8 *status) So the parameter 'vdev' indicates the device should be the real virtio device. But we also have an API like: -struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, - unsigned int vring_align, - struct udevice *udev) +.. code-block:: C + + struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, + unsigned int vring_align, + struct udevice *udev) Here the parameter 'udev' indicates the device should be the transport device. Similar naming is applied in other functions that are even not APIs, eg: -static int virtio_uclass_post_probe(struct udevice *udev) -static int virtio_uclass_child_pre_probe(struct udevice *vdev) +.. code-block:: C + + static int virtio_uclass_post_probe(struct udevice *udev) + static int virtio_uclass_child_pre_probe(struct udevice *vdev) So it's easy to tell which device these functions are operating on. @@ -223,20 +250,29 @@ ID 2) are supported. If you want to develop new driver for new devices, please follow the guideline below. 1. add new device ID in virtio.h -#define VIRTIO_ID_XXX X + +.. code-block:: C + + #define VIRTIO_ID_XXX X 2. update VIRTIO_ID_MAX_NUM to be the largest device ID plus 1 3. add new driver name string in virtio.h -#define VIRTIO_XXX_DRV_NAME "virtio-xxx" + +.. code-block:: C + + #define VIRTIO_XXX_DRV_NAME "virtio-xxx" 4. create a new driver with name set to the name string above -U_BOOT_DRIVER(virtio_xxx) = { - .name = VIRTIO_XXX_DRV_NAME, - ... - .remove = virtio_reset, - .flags = DM_FLAG_ACTIVE_DMA, -} + +.. code-block:: C + + U_BOOT_DRIVER(virtio_xxx) = { + .name = VIRTIO_XXX_DRV_NAME, + ... + .remove = virtio_reset, + .flags = DM_FLAG_ACTIVE_DMA, + } Note the driver needs to provide the remove method and normally this can be hooked to virtio_reset(). The driver flags should contain DM_FLAG_ACTIVE_DMA @@ -247,7 +283,5 @@ for the remove method to be called before jumping to OS. 6. do funny stuff with the driver -References ----------- -[1] http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf -[2] https://www.qemu.org +.. _VirtIO: http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf +.. _QEMU: https://www.qemu.org From 200fdd3bff569369f9264e648ddc9c02547b6186 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 29 Apr 2021 17:40:08 +0800 Subject: [PATCH 16/17] MAINTAINERS: Add an entry for VirtIO This was missed when VirtIO support was initially brought to U-Boot back in 2018. Add an entry for it and list myself as the maintainer. Signed-off-by: Bin Meng --- MAINTAINERS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2d267aeff2..20092cb367 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1171,6 +1171,18 @@ F: common/lcd*.c F: include/lcd*.h F: include/video*.h +VirtIO +M: Bin Meng +S: Maintained +F: drivers/virtio/ +F: cmd/virtio.c +F: include/config/virtio/ +F: include/config/virtio.h +F: include/config/cmd/virtio.h +F: include/virtio*.h +F: test/dm/virtio.c +F: doc/develop/driver-model/virtio.rst + X86 M: Simon Glass M: Bin Meng From b107761b817c421fb8eadee739656e1db38686c3 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Mon, 10 May 2021 17:03:22 -0400 Subject: [PATCH 17/17] Prepare v2021.07-rc2 Signed-off-by: Tom Rini --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 404977efa5..77d55735a4 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ VERSION = 2021 PATCHLEVEL = 07 SUBLEVEL = -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = # *DOCUMENTATION*